2012-05-31 15 views
18

Si tengo una clase como esta:¿Hay algún beneficio o inconveniente cuando un constructor implementa otro?

public class Foo 
{ 
    public IEnumerable<Bar> Bars { get; set; } 

    public Foo() 
    { 
     Bars = new List<Bar>(); 
    } 
} 

En algún momento me re-factor de la clase y añadir un constructor secundaria que implementa el primero de esta manera:

public class Foo 
{ 
    public IEnumerable<Bar> Bars { get; set; } 

    // some more properties were added 

    public Foo() 
    { 
     Bars = new List<Bar>(); 
    } 

    public Foo(string parameter): this() 
    { 
     .... some code here 
    } 
} 

que podría tener también escrito es similar a esto:

public class Foo 
{ 
    public IEnumerable<Bar> Bars { get; set; } 

    // some more properties were added too 

    public Foo() 
    { 
     InitilizeFoo(); 
    } 

    public Foo(string parameter) 
    { 
     InitilizeFoo(); 
     .... some code here 
    } 

    private void InitializeFoo() 
    { 
     Bars = new List<Bar>(); 
    } 
} 

al ver ambos enfoques de trabajo en este escenario, es que hay un beneficio o inconveniente en el uso de uno sobre el otro?

hereda constrcutors más eficiente y hacer que el código ejecuta más rápido o hay un inconveniente, que no sé acerca de hacer la segunda aplicación más eficiente en su lugar?

+1

Uso ambos. Cuando tiene sentido encadenar a los constructores, lo hago; pero a veces (el ejemplo no viene a la mente), me he ido con el método 'InitializeFoo()' y lo llamé desde todos los constructores. – Nate

+0

La seguridad de las excepciones es lo único de lo que me preocuparía. –

Respuesta

28

Una de las principales ventajas de tener una llamada al constructor a otro constructor es que se puede establecer sólo lectura campos de esa manera, no se puede hacer eso llamando a un método no-constructor.

Por ejemplo:

public class Foo 
{ 
    private readonly int myNumber; 

    public Foo() : this(42) 
    { 
    } 

    public Foo(int num) 
    { 
     myNumber = num; 
    } 
} 

En cuanto al rendimiento, es probable que no más o menos eficiente que llamar a otro constructor que llamar a otro método, pero es más fácil de leer, en mi opinión, para un constructor para llamar a otro constructor que llamar a un método privado separado cuyo único punto debe ser llamado por un constructor.

Podría, por supuesto, haber situaciones en las que tiene un método separado tiene sentido, y ciertamente no es "malo" per se. El encadenamiento de constructores simplemente se lee mejor para muchos para la mayoría de los usos, y no hay un impacto negativo en el rendimiento.

ACTUALIZACIÓN: I realizó 10.000.000 iteraciones de cada trayecto (encadenado vs método de inicialización privado) y los resultados fueron tan cerca que eran casi indistinguibles:

Initializer Method took: 84 ms for 10,000,000 iterations, 8.4E-06 ms/each. 
Chained Constructors took: 81 ms for 10,000,000 iterations, 8.1E-06 ms/each. 

Así que en realidad, en cuanto al rendimiento casi no hay beneficio de cualquier manera. El principal beneficio es con los constructores encadenados se pueden establecer readonly campos, y en la mayoría de los casos es más fácil de leer.

+0

muchas gracias por la respuesta rápida. Estoy totalmente de acuerdo en que esta y la mayoría de las descripciones de diseño son situacionales y, a veces, funcionan mejor de otra manera. Mi principal preocupación era con respecto al rendimiento, lo que afecta el tiempo de compilación o ejecución. Te has dirigido a eso muy bien, muchas gracias. – Nope

+2

¡En cualquier momento! Como con cualquier cosa, sería muy fácil escribir una pequeña prueba y usar System.Diagnostics.Stopwatch() para medir algunos millones de iteraciones de cada ... –

+0

Tuvimos un problema en el trabajo para el cual la corrección que apliqué fue solo eso ': esto()'. Estaba un poco preocupado por la corrección y los posibles problemas de eficiencia. Nunca pensé en escribir una prueba rápida en su lugar. Gracias por señalar eso. Sin duda lo probaré ... después del trabajo :). – Nope

4

La clave es reducir la cantidad de código duplicado. En este caso, llamar al constructor base desde un constructor parametrizado reduce las posibilidades de agregar un error más tarde después de olvidarse de actualizar ambos.

+1

Si ambos constructores llaman al mismo método 'Init', este problema ya está solucionado. Parece que es con lo que el OP está comparando el código. – Servy

6

encadenamiento constructores es una buena manera de hacer cumplir SRP y el programa de flujo. Ocultar el código de inicialización dentro de una función independiente Initialize() podría tener sentido si hay otras situaciones en el ciclo de vida del objeto donde también podría querer "Inicializarlo"; quizás si quisieras poder crear instancias rápidas e iniciarlas de forma lenta. Pero si el único momento válido en el ciclo de vida para ejecutar esa funcionalidad es durante la creación de instancias, y la inicialización es un conjunto bien definido de pasos discretos que deben tomarse en orden, el encadenamiento facilita eso.

+0

Nunca pensé en SRP, ese es un muy buen punto. – Nope

3

Una ventaja de tener una función Initialise() es en caso de que desee restablecer su objeto; simplemente puede llamar a la función init nuevamente en lugar de eliminar & recrear el objeto.

+2

+1. Por qué el enfoque Initialize podría ser útil. Tenga en cuenta que trataría de rediseñar la clase para evitarla: si la instancia se comparte entre muchos otros objetos, puede que sea necesario proporcionar un código de coordinación para notificar acerca de un cambio tan significativo en el estado del objeto. –

+0

Bueno. Eso es muy útil al decidir qué implementación buscar. Gracias. – Nope

2

que podría quemarse por decir esto, pero yo prefiero usar los parámetros por defecto en este caso:

public Foo(string parameter = null) 
{ 

} 

He tenido casos en los que tenía 10 - 15 parámetros opcionales y tiene 15 diferentes constructores no era una solución elegante en mi opinión. Creo que los parámetros predeterminados solo se reintrodujeron en el marco 4.0.

Cuestiones relacionadas