2009-07-21 25 views
8

Tengo una clase con un campo que debe inicializarse cuando se inicializa el objeto, como una lista que debe crearse antes de que los objetos puedan agregarse/eliminarse .Inicializando los campos de clase en la definición de campo o en el constructor de clase

public class MyClass1 
{ 
    private List<MyOtherClass> _otherClassList; 

    public MyClass1() 
    { 
     this._otherClasslist = new List<MyOtherClass>(); 
    } 
} 


public class MyClass2 
{ 
    private List<MyOtherClass> = new List<MyOtherClass>(); 

    public MyClass2() 
    { 
    } 
} 

¿Cuál es la diferencia entre estas dos clases, y por qué elegirías un método sobre el otro?

Normalmente establezco el campo en el constructor, como en MyClass1, porque me resulta más fácil poder mirar en un solo lugar para ver todo lo que sucede cuando se está instanciando el objeto, pero ¿hay algún caso donde ¿Es mejor inicializar un campo directamente como en MyClass2?

+0

Ellos tienen ya valor por defecto ... no hay necesidad de Init de nuevo. –

Respuesta

5

Las IL emitidas por el compilador de C# (VS2008 sp1) serán casi equivalentes para ambos casos (incluso en compilaciones de Depuración y Versión).

Sin embargo, si necesita añadir constructores parametrizados que tienenList<MyOtherClass>como argumento, que será diferente (sobre todo, cuando se va a crear un número significativamente grande de objetos con dichos constructores)

Ver los siguientes ejemplos para ver las diferencias (puede copiar & pasado a VS y construirlo para ver líquidos iónicos con Reflector o ILDASM).

using System; 
using System.Collections.Generic; 

namespace Ctors 
{ 
    //Tested with VS2008 SP1 
    class A 
    { 
     //This will be executed before entering any constructor bodies... 
     private List<string> myList = new List<string>(); 

     public A() { } 

     //This will create an unused temp List<string> object 
     //in both Debug and Release build 
     public A(List<string> list) 
     { 
      myList = list; 
     } 
    } 

    class B 
    { 
     private List<string> myList; 

     //ILs emitted by C# compiler are identicial to 
     //those of public A() in both Debug and Release build 
     public B() 
     { 
      myList = new List<string>(); 
     } 

     //No garbage here 
     public B(List<string> list) 
     { 
      myList = list; 
     } 
    } 

    class C 
    { 

     private List<string> myList = null; 
     //In Release build, this is identical to B(), 
     //In Debug build, ILs to initialize myList to null is inserted. 
     //So more ILs than B() in Debug build. 
     public C() 
     { 
      myList = new List<string>(); 
     } 

     //This is identical to B(List<string> list) 
     //in both Debug and Release build. 
     public C(List<string> list) 
     { 
      myList = list; 
     } 
    } 

    class D 
    { 
     //This will be executed before entering a try/catch block 
     //in the default constructor 
     private E myE = new E(); 
     public D() 
     { 
      try 
      { } 
      catch (NotImplementedException e) 
      { 
       //Cannot catch NotImplementedException thrown by E(). 
       Console.WriteLine("Can I catch here???"); 
      } 
     } 
    } 

    public class E 
    { 
     public E() 
     { 
      throw new NotImplementedException(); 
     } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      //This will result in an unhandled exception. 
      //You may want to use try/catch block when constructing D objects. 
      D myD = new D(); 
     } 
    } 
} 

Nota: no ha cambiado ningún indicador de optimización cuando se cambia a la versión de compilación.

0

Los códigos son equivalentes porque el compilador pone la inicialización en cada constructor que tiene en el segundo caso, el beneficio del segundo caso es que el programador no pensará inicializar los campos cuando agregará un nuevo constructor después de escribir esa clase :)

+0

El desarrollador que crea inicialmente la clase debe usar un encadenamiento de constructor adecuado, por lo que no debería ser un problema. Sin embargo, el programador que modifica la clase un año después comprende mejor la clase antes de tocarla. Él debería asegurarse de que todos los campos se estén inicializando correctamente. –

0

En C# prácticamente no hay diferencia entre los dos ejemplos. Pero el desarrollador tiende a inicializar sus campos en el constructor porque es menos propenso a errores.

2

Al inicializar en un constructor, creo que sería más fácil capturar y manejar excepciones si fuera necesario.

1

En MyClass1 alguien podría anular el constructor y causar problemas.

3

hay una diferencia:

Los campos se inicializan inmediatamente antes de que el constructor para la instancia de objeto se llama, por lo que si el constructor asigna el valor de un campo , sobrescribirá cualquier valor dado durante la declaración de campo. From MSDN:

3

En cuanto al comportamiento, ambos deben ser idénticos.
Sin embargo, es posible que desee considerar una carcasa de borde IL - Bloat. El IL para los inicializadores de campo se inserta en la parte superior de cada ctor.Y de eso se desprende que si tiene muchos inicializadores de campo y muchos codificadores sobrecargados, la misma sección de IL está prefijada a la sobrecarga del ctor IL. Como resultado, el tamaño total de su conjunto podría aumentar en comparación con el caso en el que utiliza el encadenamiento de constructor o el delegado en una función común Initialize() (donde el IL repetido sería una llamada a método). por lo tanto, para este escenario específico, los inicializadores de campo serían una opción relativamente más débil.

Usted puede verificar esto con reflector en el binario para este fragmento de código

public class MyClass2 
    { 
    private List<int> whack = new List<int>(); 
    // lots of other field initializers 

    public MyClass2() 
    { 
     Console.WriteLine("Default ctor"); 
    } 
    public MyClass2(string s) 
    { 
     Console.WriteLine("String overload"); 
    } 
     // lots of other overload ctors 
    } 
Cuestiones relacionadas