2011-01-05 12 views
31

Si se encadenan llamadas de constructor utilizando la sintaxis:Constructor encadenamiento Solicitar

public frmConfirm(): this(1) 

cuando se llama al constructor sobrecargado? Además, ¿alguien puede confirmar que si la clase es una forma, surgirán problemas al tener la llamada InitializeComponent() en ambos constructores?

+5

@ madmik3: es seguro escribir código para ver qué pasa. La pregunta es si eso está * garantizado * en todas las circunstancias (SO diferente, diferentes versiones del CLR). –

+0

Una publicación relacionada - [orden de ejecución del constructor C#] (https://stackoverflow.com/q/1882692/465053). – RBT

Respuesta

42

Se llamará al constructor encadenado inmediatamente antes del cuerpo del constructor de definición. La secuencia IL generada es un call inmediato al otro constructor, seguido por el IL generado a partir de las declaraciones en el constructor.

Así que si encadena a otro constructor y ese constructor llama al InitializeComponent(), el constructor que llama no debe llamar a este método.

Por ejemplo, dada esta clase de muestra:

class Foo { 
    public int A, B; 

    public Foo() : this(1) { 
     B = 2; 
    } 

    public Foo(int a) { 
     A = a; 
    } 
} 

Ésta es la IL generada:

.class private auto ansi beforefieldinit Foo 
     extends [mscorlib]System.Object 
    { 
    .field public int32 A 
    .field public int32 B 

    // method line 1 
    .method public hidebysig specialname rtspecialname 
      instance default void '.ctor'() cil managed 
    { 
     .maxstack 8 
     IL_0000: ldarg.0 
     IL_0001: ldc.i4.1 
     IL_0002: call instance void class Foo::'.ctor'(int32) 
     IL_0007: ldarg.0 
     IL_0008: ldc.i4.2 
     IL_0009: stfld int32 Foo::B 
     IL_000e: ret 
    } // end of method Foo::.ctor 

    // method line 2 
    .method public hidebysig specialname rtspecialname 
      instance default void '.ctor' (int32 a) cil managed 
    { 
     .maxstack 8 
     IL_0000: ldarg.0 
     IL_0001: call instance void object::'.ctor'() 
     IL_0006: ldarg.0 
     IL_0007: ldarg.1 
     IL_0008: stfld int32 Foo::A 
     IL_000d: ret 
    } // end of method Foo::.ctor 

    } // end of class Foo 

Tenga en cuenta que el constructor sin argumentos llama a otro constructor antes de asignar 2 al campo B .

+0

Perfecto. Eso es lo que pensé, gracias – JeffE

+0

¿no hará el MSIL una referencia circular? (Sé que no lo hará, pero no puedo entender por qué) Parece que .ctor() está llamando .ctor (int32 a) y viceversa.¿Alguien puede aclarar por qué esto no está sucediendo? – arviman

+3

@arviman 'Foo: .ctor()' llama a 'Foo: .ctor (int32)', pero a su vez llama a 'System.Object: .ctor()', *** not *** 'Foo :. ctor() '. – cdhowie

9

El constructor this(1) se llama primero.

En cuanto a su segunda pregunta, debido a InitializeComponent y otros problemas con la herencia de formularios, le sugiero que use la composición en lugar de la herencia.

+0

Conozco algunos de los problemas con la herencia de formularios, pero es la mejor solución para mi proyecto – JeffE

5

El lugar para buscar respuestas a una pregunta como esta es el C# Language Specification. En la sección 10.11.1 , inicializadores de constructor se puede leer (el subrayado es mío):

Todos los constructores de instancia (excepto aquellos para objeto de clase) implícitamente incluye una invocación de otro ejemplo constructor inmediatamente antes el constructor-cuerpo.

Lectura adicional muestra que:

  • si el constructor tiene un constructor inicializador ejemplo de la forma de base(arguments), será invocado un constructor de la clase base directa.
  • si el constructor tiene un inicializador de constructor de instancia del formulario this(argument), se invocará un constructor en la propia clase.
  • si no se proporciona un inicializador de constructor de instancias, base() se agregará automáticamente.
+0

Gracias por traerme la especificación del lenguaje C# a mi atención – Ronnie