2014-09-11 17 views
9

Ho passato solo ore a confondermi con uno NullReferenceException in cui pensavo che non ce ne fosse uno. Stavo costruendo una classe in questo modo:Perché è necessario chiamare esplicitamente il costruttore genitore in MSIL?

public class MyClass : MyBase<Foo> 
{ 
    public MyClass() 
    { 
     base.Method(Foo.StaticField); 
    } 
} 

dove

public class MyBase<T> 
{ 
    private SomeObject bar = new SomeObject(); 

    public void Method(object o) 
    { 
     this.bar.AnotherMethod(o); // exception thrown here 
    } 
} 

Fondamentalmente il mio IL è stato il seguente:

ctorIl.Emit(OpCodes.Ldarg_0); 
ctorIl.Emit(OpCodes.Ldsfld, staticField); 
ctorIl.Emit(OpCodes.Box, typeof(FieldType)); 
ctorIl.Emit(OpCodes.Call, parentMethod); 
ctorIl.Emit(OpCodes.Ret); 

e ho finalmente capito che deve essere che bar non veniva istanziato. Ho costruito la mia classe in C# e compilato e trovato l'unica differenza era che il seguente dovrebbe essere al di sopra della IL sopra:

ctorIl.Emit(OpCodes.Ldarg_0); 
ctorIl.Emit(OpCodes.Call, parentCtor); 
// as above 

Con queste righe, il mio codice ora funziona come previsto.

Quindi le mie domande sono:

  1. perché abbiamo bisogno di chiamare esplicitamente il costruttore di base per istanziare i campi?
  2. Esiste un uso legittimo di non chiamare il costruttore di base?
  3. ... e in caso contrario, perché il CLR lo accetta come un programma valido?
+4

@PatrickHofman migliori di sempre: P –

+0

Il costruttore della classe base è ** sempre ** chiamato. Se non lo scrivi esplicitamente nel tuo codice C#, allora il compilatore lo fa per te. E * fa * nota che ce n'è sempre uno, System.Object ha un costruttore. Molto facile da vedere con ildasm.exe, lo strumento che si desidera sempre utilizzare prima di iniziare a generare il proprio MSIL. –

+1

@HansPassant in C# è, sì; in IL: non così tanto –

risposta

6
  1. perché non è automatico, e consente compilatori e codice IL di decidere sia quando e se di chiamare il costruttore di base
  2. bene, si può effettivamente un'istanza di tipi senza utilizzare qualsiasi costruttore di qualsiasi tipo ... bordo maiuscolo, certo; ma ammessi
  3. perché è consentito

Nota che si può effettivamente emettere un semplice costruttore (compreso chiamata base) in un singolo metodo:

typeBuilder.DefineDefaultConstructor(); 
+0

Ah così "DefineDefaultConstructor" fondamentalmente fa le prime due righe di IL che ho fatto qui automaticamente? –

+0

@dav_i sì; da MSDN: "Definisce il costruttore predefinito. Il costruttore qui definito chiamerà semplicemente il costruttore predefinito del genitore." –

+0

Non dovrebbe essere RTFM? : P Grazie Marc. –

Problemi correlati