Inicialización de variable de miembro C #; ¿mejores prácticas?

¿Es mejor inicializar las variables de los miembros de la clase en la statement?

private List _things = new List(); private int _arb = 99; 

o en el constructor predeterminado?

 private List _things; private int _arb; public TheClass() { _things = new List(); _arb = 99; } 

¿Es simplemente una cuestión de estilo o hay intercambios de rendimiento, de una forma u otra?

En términos de rendimiento, no hay diferencia real; los inicializadores de campo se implementan como lógica de constructor. La única diferencia es que los inicializadores de campo suceden antes que cualquier constructor “base” / “este”.

El enfoque de constructor se puede usar con propiedades implementadas automáticamente (los inicializadores de campo no pueden), es decir,

 [DefaultValue("")] public string Foo {get;set;} public Bar() { // ctor Foo = ""; } 

Aparte de eso, tiendo a preferir la syntax del inicializador de campo; Creo que mantiene las cosas localizadas, es decir,

 private readonly List items = new List(); public List Items {get {return items;}} 

No tengo que buscar hacia arriba y hacia abajo para encontrar dónde está asignado …

La excepción obvia es cuando necesita realizar una lógica compleja o tratar con parámetros de constructor, en cuyo caso la inicialización basada en el constructor es el camino a seguir. Del mismo modo, si tiene varios constructores, sería preferible que los campos siempre se configuren de la misma manera, por lo que podría tener ctors como:

 public Bar() : this("") {} public Bar(string foo) {Foo = foo;} 

editar: como comentario lateral, tenga en cuenta que, en el ejemplo anterior, si hay otros campos (no mostrados) con inicializadores de campo, entonces solo se inicializan directamente en los constructores que llaman base(...) – es decir, la public Bar(string foo) ctor. El otro constructor no ejecuta los inicializadores de campo, ya que sabe que están hechos por this(...) ctor.

En realidad, los inicializadores de campo, como lo demuestra, son una abreviatura conveniente. El comstackdor realmente copia el código de inicialización al principio de cada constructor de instancia que defina para su tipo.

Esto tiene dos implicaciones: en primer lugar, cualquier código de inicialización de campo está duplicado en cada constructor y, en segundo lugar, cualquier código que incluya en sus constructores para inicializar campos a valores específicos de hecho reasignará los campos.

Por lo que respecta al rendimiento, y con respecto al tamaño del código comstackdo, es mejor que mueva los inicializadores de campo a los constructores.

Por otro lado, el impacto en el rendimiento y el código “inflado” generalmente serán insignificantes, y la syntax del inicializador de campo tiene el importante beneficio de disminuir el riesgo de que olvide inicializar algún campo en uno de sus constructores.

Una de las principales limitaciones con los inicializadores de campo es que no hay forma de envolverlos en un bloque try-finally. Si se lanza una excepción en un inicializador de campo, se abandonará cualquier recurso que se haya asignado en los inicializadores anteriores; no hay forma de prevenirlo Se pueden resolver otros errores en la construcción, si es torpe, al tener un constructor base protegido que acepte un identificador desechable por referencia, y apuntarlo a sí mismo como su primera operación. Entonces uno puede evitar llamar al constructor excepto a través de métodos de fábrica que en caso de excepción llamarán a Dispose en el objeto parcialmente creado. Esta protección permitirá la limpieza de IDisposables creados en inicializadores de clase derivada si el constructor de la clase principal falla después de “contrabandear” una referencia al nuevo objeto. Lamentablemente, no hay forma de proporcionar dicha protección si falla un inicializador de campo.

Use los inicializadores de campo o cree una función Init (). El problema de poner estas cosas en su constructor es que si alguna vez necesita agregar un segundo constructor, termina con el código de copiar / pegar (o lo pasa por alto y termina con variables no inicializadas).

Me gustaría inicializar donde declarado. O haga que el constructor (es) llame a una función Init ().

Por ejemplo, las variables, es en gran medida una cuestión de estilo (prefiero usar un constructor). Para las variables estáticas, hay un beneficio de rendimiento al inicializar en línea (no siempre es posible, por supuesto).

Depende de ti.
A menudo los inicializo en línea, porque no me gusta tener un constructor cuando realmente no los necesito (¡me gustan las clases pequeñas!).

Sobre el punto agregado a lo anterior: siempre tienes un constructor al implementar clases que tienen una implementación. Si no declara uno, el comstackdor infiere el instructor predeterminado [public Foo () {}]; un constructor que no toma argumentos

Muchas veces me gusta ofrecer ambos enfoques. Permitir constructores para aquellos que deseen usarlos y permitir los Inicializadores de Campo para las situaciones en las que desee utilizar una implementación simplificada o predeterminada de su clase / tipo. Esto agrega flexibilidad a su código. Tenga en cuenta que cualquier persona puede usar el inicializador de campo predeterminado si lo desea … asegúrese de declararlo manualmente si ofrece más de un constructor – public Foo () {}