2011-01-05 14 views
31

Jeśli łańcuch wywołań konstruktora używając składni:Konstruktor Chaining Zamówienie

public frmConfirm(): this(1) 

gdy jest przeciążony konstruktor nazywa? Czy ktoś może potwierdzić, że jeśli klasa jest formą, problemy pojawią się po wywołaniu funkcji InitializeComponent() w obu konstruktorach?

+5

@ madmik3: na pewno łatwo jest napisać kod, aby zobaczyć, co się stanie. Pytanie brzmi, czy jest to * gwarantowane *, że stanie się to we wszystkich okolicznościach (różne systemy operacyjne, różne wersje CLR). –

+0

Pokrewny wpis - [C# wykonanie zlecenia konstruktora] (https://stackoverflow.com/q/1882692/465053). – RBT

Odpowiedz

42

Połączony konstruktor zostanie wywołany bezpośrednio przed treścią definiującego konstruktora. Wygenerowana sekwencja IL jest natychmiastowa call dla innego konstruktora, po której następuje IL wygenerowana z instrukcji w konstruktorze.

Jeśli więc łańcuch do innego konstruktora i ten konstruktor wywołuje InitializeComponent(), konstruktor wywołujący nie powinien wywoływać tej metody.

Na przykład, biorąc pod uwagę tej klasy próbki:

class Foo { 
    public int A, B; 

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

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

To jest generowany IL:

.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 

Zauważ, że nie-Arg konstruktor wywołuje inne konstruktora przed przypisaniem 2 do pola B .

+0

Idealny. Tak myślałem, dzięki – JeffE

+0

nie będzie powodować MSIL okólnik odniesienia? (wiem, że to nie będzie, ale nie mogę zrozumieć, dlaczego) Wydaje się, że .ctor() to wywołanie .ctor (int32 a) i na odwrót.Czy ktokolwiek może wyjaśnić, dlaczego tak się nie dzieje? – arviman

+3

@arviman 'Foo: .ctor()' wywołuje 'Foo: .ctor (int32)', ale to z kolei wywołuje 'System.Object: .ctor()', *** nie *** 'Foo :. ctor() '. – cdhowie

9

Konstruktor this(1) jest wywoływany jako pierwszy.

Jeśli chodzi o twoje drugie pytanie, z powodu InitializeComponent i innych problemów z dziedziczeniem formularzy, proponuję użyć kompozycji zamiast dziedziczenia.

+0

Jestem świadomy niektórych problemów związanych z dziedziczeniem formularzy, ale jest to najlepsze rozwiązanie dla mojego projektu. – JeffE

5

Miejsce, w którym należy szukać odpowiedzi na takie pytanie, to C# Language Specification. W sekcji 10.11.1, Konstruktor inicjalizatory można przeczytać (podkreślenie moje):

Wszystkie konstruktorów instancji (z wyjątkiem tych dla klasy obiektu) niejawnie zawierać wywołanie innego instancji konstruktora natychmiast przed Konstruktor-ciało.

Dalsze odczytu wykazała, że:

  • Jeżeli konstruktor ma instancję konstruktora inicjatora w postaci base(arguments), konstruktor z bezpośredniej klasy bazowej zostanie wywołana. Jeśli konstruktor ma inicjator konstruktora instancji w postaci this(argument), zostanie wywołany konstruktor w klasie.
  • jeśli nie podano inicjatora konstruktora instancji, zostanie automatycznie dodana base().
+0

Dziękuję za zwrócenie mojej uwagi na specyfikację języka C#. – Ronnie