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:
- perché abbiamo bisogno di chiamare esplicitamente il costruttore di base per istanziare i campi?
- Esiste un uso legittimo di non chiamare il costruttore di base?
- ... e in caso contrario, perché il CLR lo accetta come un programma valido?
@PatrickHofman migliori di sempre: P –
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. –
@HansPassant in C# è, sì; in IL: non così tanto –