2012-04-30 14 views
32
int a, b, c; 

Constructor() 
{ 
    a = 5; 
    b = 10; 
    c = 15; 
    //do stuff 
} 
Constructor(int x, int y) 
{ 
    a = x; 
    b = y; 
    c = 15; 
    //do stuff 
} 
Constructor(int x, int y, int z) 
{ 
    a = x; 
    b = y; 
    c = z; 
    //do stuff 
} 

para evitar la duplicación de "cosas" y algunas asignaciones, probé algo como:¿Cómo puedo usar múltiples constructores para eliminar código duplicado mientras mantengo la legibilidad?

int a, b, c; 

Constructor(): this(5, 10, 15) 
{ 
} 
Constructor(int x, int y): this(x, y, 15) 
{ 
} 
Constructor(int x, int y, int z) 
{ 
    a = x; 
    b = y; 
    c = z; 
    //do stuff 
} 

Esto funciona para lo que yo quiero hacer, pero a veces necesito utilizar un código largo para crear nuevos objetos o hacer algunos cálculos:

int a, b, c; 

Constructor(): this(new Something(new AnotherThing(param1, param2, param3), 
    10, 15).CollectionOfStuff.Count, new SomethingElse("some string", "another 
    string").GetValue(), (int)Math.Floor(533/39.384)) 
{ 
} 
Constructor(int x, int y): this(x, y, (int)Math.Floor(533/39.384)) 
{ 
} 
Constructor(int x, int y, int z) 
{ 
    a = x; 
    b = y; 
    c = z; 
    //do stuff 
} 

Este código es más o menos lo mismo que antes, sólo los parámetros que se están pasando no son muy legibles. Preferiría hacer algo como:

int a, b, c; 

Constructor(): this(x, y, z) //compile error, variables do not exist in context 
{ 
    AnotherThing at = new AnotherThing(param1, param2, param3); 
    Something st = new Something(aThing, 10, 15) 
    SomethingElse ste = new SomethingElse("some string", "another string"); 

    int x = thing.CollectionOfStuff.Count; 
    int y = ste.GetValue(); 
    int z = (int)Math.Floor(533/39.384); 

    //In Java, I think you can call this(x, y, z) at this point. 
    this(x, y, z); //compile error, method name expected 
} 
Constructor(int x, int y): this(x, y, z) //compile error 
{ 
    int z = (int)Math.Floor(533/39.384); 
} 
Constructor(int x, int y, int z) 
{ 
    a = x; 
    b = y; 
    c = z; 
    //do stuff 
} 

Básicamente estoy construyendo los parámetros dentro del cuerpo del constructor. Entonces estoy tratando de pasar esos parámetros construidos a otro constructor. Creo que recuerdo haber podido utilizar las palabras clave "este" y "super" para llamar a los constructores mientras estaba dentro del cuerpo de otro constructor al codificar en Java. No parece posible en C#.

¿Hay alguna manera de hacer esto fácilmente? ¿Hice algo incorrectamente? Si esto no es posible, ¿debería seguir con el código ilegible?

Supongo que siempre podría cortar el código duplicado en otro método completamente fuera de los constructores. Entonces cada constructor simplemente haría lo suyo y llamaría al código compartido por los otros constructores.

Respuesta

35

Como alternativa a la llamada al método de inicialización de todos los constructores (que no le permite usar readonly campos) o métodos de fábrica (que introducen una complejidad adicional cuando se han derivado de las clases), se puede utilizar un parameter object:

int a, b, c; 

public Constructor() 
    : this(new ConstructorParameters()) 
{ 
} 

public Constructor(int x, int y) 
    : this(new ConstructorParameters(x, y)) 
{ 
} 

public Constructor(int x, int y, int z) 
{ 
    a = x; 
    b = y; 
    c = z; 
    //do stuff 
} 

private Constructor(ConstructorParameters parameters) 
    : this(parameters.X, parameters.Y, parameters.Z) 
{ 
} 

private class ConstructorParameters 
{ 
    public int X; 
    public int Y; 
    public int Z; 

    public ConstructorParameters() 
    { 
     AnotherThing at = new AnotherThing(param1, param2, param3); 
     Something st = new Something(at, 10, 15) 
     SomethingElse ste = new SomethingElse("some string", "another string"); 

     X = st.CollectionOfStuff.Count; 
     Y = ste.GetValue(); 
     Z = (int)Math.Floor(533/39.384); 
    } 

    public ConstructorParameters(int x, int y) 
    { 
     X = x; 
     Y = y; 
     Z = (int)Math.Floor(533/39.384); 
    } 
} 
+0

Creo que esta ruta me puede gustar mucho mejor que los métodos de fábrica. Estaba dudando en modificar mi código usando métodos de fábrica, principalmente porque estoy usando la herencia. Al ser un programador novato, estaba teniendo dificultades para visualizar todos los cambios que tendrían que producirse. Tengo un par de constructores sobrecargados en mis clases base. Las clases derivadas están agregando sus propios bits a los constructores base. Dependiendo de la clase derivada, se necesitan diferentes cálculos para encontrar ciertos parámetros. Usar una clase privada para manejar parámetros complejos parece ser el enfoque más simple. – Cheese

+0

Decidí ir con otra solución.Después de leer el enlace que publicó, comencé a leer la página "Demasiados parámetros" en el mismo sitio. Leer a través de eso me hizo considerar que tal vez los constructores se hicieron demasiado complicados por todos los parámetros que les pasé. He decidido recortar la mayoría de los parámetros de los constructores. Establecer esos campos se hará en otro lugar en el código. En lugar de "¿cómo puedo hacer esto con los constructores?", Creo que mi problema real era "¿realmente necesito pasar esos muchos parámetros?". Como el enlace que me proporcionó me llevó a mi respuesta ... – Cheese

+0

y la respuesta que publicó fue la que consideré la mejor solución para mi pregunta original, estoy eligiendo su respuesta como respuesta. – Cheese

14

Usted puede hacer

Constructor() : this(5, 10, 15) 
{ 
} 
Constructor(int x, int y) : this(x, y, 15) 
{ 
} 
Constructor(int x, int y, int z) 
{ 
    int a = x; 
    int b = y; 
    int c = z; 
    //do stuff 
} 

Sin embargo, si lo que necesita hacer algo de lógica de fantasía en función de los parámetros, me gustaría utilizar un factory pattern:

public class myclass 
{ 
    private myclass(int x, int y, int z) 
    { 
    int a = x; 
    int b = y; 
    int c = z; 
    //do stuff 
    } 
    public static myclass Create() 
    { 
    AnotherThing at = new AnotherThing(param1, param2, param3); 
    Something st = new Something(aThing, 10, 15) 
    SomethingElse ste = new SomethingElse("some string", "another string"); 

    int x = thing.CollectionOfStuff.Count; 
    int y = ste.GetValue(); 
    int z = (int)Math.Floor(533/39.384); 

    return new myclass(x, y ,z); 
    } 
    public static myclass Create(int x, int y) 
    { 
    if (x = 1) 
     return new myclass(x, y, 2) 
    else 
     return new myclass(x, y, 15); 
    } 
    public static myclass Create(int x, int y, int z) 
    { 
    //so on and so forth 
    return new myclass(x, y, z); 
    } 
} 

Aunque no necesidad de una patrón de fábrica, definitivamente hace que su lógica de constructor sea legible.

+0

Creo que esta es una solución decente para lo que estoy tratando de lograr. Mi proyecto contiene varias clases que se usarán para crear colecciones de objetos anónimos. Creo que un patrón de fábrica podría aplicarse a múltiples ubicaciones dentro de mi código. – Cheese

+0

¿Por qué no es posible en C# simplemente llamar a una función de constructor en otro constructor? (Si es así) –

+0

@MakanTayebi seguro, pero a veces no desea construir un objeto si los parámetros no son válidos. Si ese es el caso, la mayoría de las veces es mejor usar el patrón de fábrica y luego lanzar una excepción en el constructor. –

Cuestiones relacionadas