En su caso, no hay una diferencia real en la funcionalidad. Sin embargo, está el problema de averiguar dónde y cómo se inicializa todo. Si pongo la inicialización en el constructor, tengo dos grandes beneficios:
Todo está inicializado en un solo lugar; No tengo que ir a buscar si y dónde se establece.
Si quiero, puedo pasar argumentos al constructor de Bar en función de cómo estoy configurando cosas. Si el inicializador está fuera del constructor, estoy mucho más limitado en cómo puedo inicializar cosas.
Francamente, el IDE ayuda un poco con # 1 ... a pesar de que me dé un tirón lejos del código que estaba mirando, mis clases rara vez son tan grandes como para hacer cosas re-hallazgo un problema . Entonces, si no necesito el n. ° 2, es probable que lo haga de cualquier manera dependiendo del proyecto y mi estado de ánimo. Sin embargo, para proyectos más grandes, me gustaría tener todo mi código de inicio en un solo lugar.
Editar:
bien, al parecer, hay una diferencia entre los dos. Pero el caso donde importa es raro.
he creado las siguientes clases:
class Program
{
public Program() { Console.WriteLine(this); }
static void Main(string[] args)
{
other p = new other();
Console.WriteLine(p);
Console.ReadLine();
}
}
class other : Program
{
string s1 = "Hello";
string s2;
public other() { s2 = "World"; }
public override string ToString() { return s1 + s2; }
}
Ahora, lo que me encontré fue un poco sorprendente e inesperado (si usted no ha leído la especificación C#).
Esto es lo que el constructor de la clase other
compilado a:.
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 29 (0x1d)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldstr "Hello"
IL_0006: stfld string ConsoleApplication1.other::s1
IL_000b: ldarg.0
IL_000c: call instance void ConsoleApplication1.Program::.ctor()
IL_0011: ldarg.0
IL_0012: ldstr "World"
IL_0017: stfld string ConsoleApplication1.other::s2
IL_001c: ret
} // end of method other::.ctor
Nota de la llamada a programar :: Héctor (el constructor de la clase base) intercalado entre los dos ldstr
/stfld
pares (esos son los que establecer s1
y s2
). Es decir, cuando se está ejecutando el constructor base, s2
aún no se ha establecido.
El programa, para referencia, las salidas de los siguientes:
Hello
HelloWorld
porque en el constructor del Programa, Console.WriteLine(obj)
llamados obj.ToString()
, que (ya que el objeto es ya un other
) fue other::ToString()
. Como el s2
no se configuró aún, no obtuvimos un "Mundo" la primera vez. Si estuviéramos haciendo algo más propenso a errores que simplemente imprimir cosas, esto podría causar problemas reales.
Ahora, este es un ejemplo feo, diseñado para ser un caso patológico. Pero es un excelente argumento en contra de llamar funciones virtuales en su constructor. Sin hacer exactamente eso, esta ruptura no hubiera sido posible. Esa es la única vez que realmente tiene que preocuparse por la diferencia: cuando el constructor de su clase base llama a los métodos virtuales que ha anulado, que se basan en los valores de los campos que se establecen en el constructor. Una ventana bastante estrecha de rompimiento, pero sí.
Posible duplicado de: http://stackoverflow.com/questions/4219759/create-an-object-in-the-constructor-or-at-top-of-the-class or: http: // stackoverflow. com/questions/298183/c-member-variable-initialization-best-practice –
Gracias por atrapar a los incautos, Yodan –