2010-05-10 9 views
11

Duplicar posible:
Initialize class fields in constructor or at declaration?¿Es una mala práctica para inicializar los campos fuera de un constructor explícito

Estamos discutiendo acerca de las prácticas de codificación. Los ejemplos aquí son un poco demasiado simples, pero el verdadero negocio tiene varios constructores. Para inicializar los valores simples (por ejemplo, fechas a su valor mínimo), he movido el código de los constructores a las definiciones de campo.

public class ConstructorExample 
{ 
    string _string = "John"; 
} 

public class ConstructorExample2 
{ 
    string _string; 

    public ConstructorExample2() 
    { 
     _string = "John"; 
    } 
} 

¿Cómo debe ser realizada por el libro? Tiendo a ser muy caso por caso y tal vez soy un poco flojo sobre este tipo de cosas. Sin embargo, creo que Occams razor me dice que mueva la inicialización de múltiples constructores. Por supuesto, siempre podría mover esta inicialización compartida en un método privado.

La pregunta es esencialmente ... ¿Inicializar campos en los que se definen de forma opuesta a la del constructor?

El argumento que estoy enfrentando es uno de manejo de errores, pero no creo que sea relevante, ya que no hay excepciones posibles que no se recojan en tiempo de compilación.

+0

posible duplicado de [Mejores prácticas: Inicializar campos de clase en el constructor o en la declaración?] (Http://stackoverflow.com/questions/24551/best-practice-initialize-class-fields-in-constructor-or-at -declaración) –

+1

es pero no encuentro las respuestas en ese hilo para ser convincente, la primera es un poco dogmática. La referencia a FXCop es un argumento fuerte, como lo es el argumento del mantenimiento y el encadenamiento del constructor, pero aparte de eso, nada es demasiado fáctico. –

+3

Para conocer algunas consecuencias interesantes de las diferencias sutiles entre la inicialización en el campo y en el cuerpo, consulte http://blogs.msdn.com/ericlippert/archive/2008/02/15/why-do-initializers-run-in- the-opposite-order-as-constructors-part-one.aspx y http://blogs.msdn.com/ericlippert/archive/2008/02/18/why-do-initializers-run-in-the-opposite- order-as-constructors-part-two.aspx –

Respuesta

13

No es necesariamente malo para inicializar valores fuera del constructor, y el problema que tenemos aquí:

string _string; 

    public ConstructorExample2() 
    { 
     _string = "John"; 
    } 

Es que si usted tiene varios constructores no hay que olvidar a cualquiera
1. Fecha _STRING en cada constructor
2. Separe la lógica en un método común y llame a ese método en cada constructor
3. Llame al constructor con la lógica que contiene, desde los otros constructores. (Encadena los constructores)
Ahora bien, esto no es necesariamente un problema, pero debes recordar hacerlo. Inicializándolo fuera del constructor, está hecho para ti. Es una cosa menos que debes recordar hacer.

+7

No necesita reinicializar la cadena _s en cada constructor. En su lugar, puede encadenar ctors utilizando un 'public MyClass(): this (String.Vacío) ' – Oliver

+0

Con el comentario, me gusta bastante esto como una respuesta equilibrada. –

+0

¿Oliver se preocupa por proporcionar algún razonamiento? –

0

Prefiero inicializar campos simples como ese fuera del constructor.

No debería causar ningún problema ya que la compilación en realidad mueve esas inicializaciones al constructor en tiempo de compilación de todos modos.

2

Microsoft FxCop por defecto recomienda inicializadores de campo sobre el uso del constructor. This question también es un duplicado de este y debe proporcionar alguna información.

Con clases estáticas, deberá tener en cuenta algunas sutilezas que se tratan en this question.

+0

¿Por qué FxCop hace esta recomendación? –

+0

@Robert: me alegro de que haya preguntado. Actualicé mi respuesta para incluir cierta documentación de respaldo en la forma de otras preguntas/respuestas de SO. Mi opinión es que los inicializadores de campo se ejecutan antes que los constructores y les da a los constructores un objeto "más listo" para trabajar. –

+2

Mi error - parece que FxCop solo recomienda esto en el caso de las clases estáticas: http://msdn.microsoft.com/en-us/library/ms182275.aspx –

0

Si la inicialización de la variable será la misma, no importa qué argumentos se pasen al constructor, entonces no tiene sentido alterar el método del constructor con el código de inicialización innecesario. En este caso, me inicializo en el lugar.

0

Inisializar los campos en el constructor es mejor. De esta forma si/cuando se agrega un constructor diferente, usted sabe que todos los campos comienzan con valores nulos/predeterminados y puede inicializarlos apropiadamente.

1

En el ejemplo anterior, la asignación de "John" a _string no tiene una dependencia lógica en ninguna variable y, por lo tanto, debe estar fuera del constructor en el inicializador de campo.

Mientras no sea posible inicializar el objeto en un estado no utilizable, entonces no importa.

Cuando se compila el código, ambos enfoques serán los mismos de todos modos.

15

Tenga en cuenta que todas las inicializaciones de nivel de declaración de campo se realizarán una vez por cada cadena de constructor, incluso si el constructor por sí solo establece el campo en otra cosa.

Si encadena constructores juntos, los campos se inicializarán en el primer constructor común al que se llama.

vistazo a este ejemplo:

using System; 

namespace ClassLibrary3 
{ 
    public class Class1 
    { 
     private string _Name = "Lasse"; 

     public Class1() 
     { 
     } 

     public Class1(int i) 
      : this() 
     { 
     } 

     public Class1(bool b) 
     { 
      _Name = "Test"; 
     } 
    } 
} 

Este código se compila como esto:

using System; 

namespace ClassLibrary3 
{ 
    public class Class1 
    { 
     private string _Name; 

     public Class1() 
     { 
      _Name = "Lasse" 
     } 

     public Class1(int i) 
      : this() 
     { 
      // not here, as this() takes care of it 
     } 

     public Class1(bool b) 
     { 
      _Name = "Lasse" 
      _Name = "Test"; 
     } 
    } 
} 
+1

ojalá pudiera votarte más de una vez. ;-) – Oliver

+0

Sí, lo siento, no pude marcar esto como la respuesta. El punto sobre inicializadores siendo llamado en qué orden se sentía inicialmente a mí por ser contrario a la intuición es bastante fuerte - especialmente en escenarios de herencia del ADN de saber lo que tiene y no ha sido inicializado. –

1

No estoy seguro sobre C#, pero en el código fuente de Java que parecen preferir el constructor, ejemplo:

public class String{ 
    char[] value; 
    int offset; 
    ... 
    public String(){ 
     value = new char[0]; 
     offset = 0; 
     ... 
    } 
} 
+0

que argumento con AC/programador de Java;) Hay una manera de inicializar como esta en java http://java.sun.com/docs/books/tutorial/java/javaOO/initial.html –

+0

Sé que hay, pero este fragmento es del código fuente de Java en sí. Por lo general, cuando sospecho algo, compruebo cómo las grandes mentes que escribieron Java lo resolvieron. – medopal

1

Creo que para inicializaciones simples como eso, está bien hacerlo en la declaración. Sin embargo, no entiendo el argumento de manejo de errores. Incluso si hay una excepción en la inicialización, creo que encontrará que su mecanismo normal de manejo de errores funcionará de la misma manera. Todavía lanzará una excepción cuando llame al constructor.

+0

Tiendo a estar de acuerdo, pero no quiero descartarlo de inmediato. –

1

Tiendo a inicializar cosas en el programa de acceso get, donde se usan por primera vez. Si es nulo, entonces inicializa y todo eso.

+0

No había considerado esa opción. El único problema es en el caso en que un valor nulo es un valor válido, pero no es el valor predeterminado. –

+0

Siempre se puede hacer un booleano para indicar estado inicializado en lugar de depender de "si (valor == null) {inicializar;}". Me gusta la inicialización al acceder, creo que con más frecuencia se denomina "inicialización diferida". Es muy útil cuando se trabaja con una base de datos. También hace que sea fácil guardar las cosas en la memoria caché si lo deseas. – quillbreaker

+0

No creo que alguna vez adoptar este enfoque para un valor de inicialización literal (como una cadena literal). Comercializa una tarea de una sola vez con una prueba de nulo en cada obtención, y hace que el código sea más complejo. Para otros escenarios, particularmente con inicializaciones de objetos grandes o lentos, esto podría tener sentido. –

Cuestiones relacionadas