Po prostu spędziłem wiele godzin, będąc zdezorientowanym przez NullReferenceException
, gdzie myślałem, że nie powinno być. Byłem konstruowania klasę tak:Dlaczego musimy jawnie wywoływać konstruktora macierzystego w MSIL?
public class MyClass : MyBase<Foo>
{
public MyClass()
{
base.Method(Foo.StaticField);
}
}
gdzie
public class MyBase<T>
{
private SomeObject bar = new SomeObject();
public void Method(object o)
{
this.bar.AnotherMethod(o); // exception thrown here
}
}
Zasadniczo mój IL był następujący:
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);
i ja w końcu pomyślałem, że musi być tak, że bar
nie będąc utworzony. I zbudowany moją klasę w C# i skompilowane go i okazało się, że jedyną różnicą było to, że następujące dokumenty powinny znajdować się powyżej IL powyżej:
ctorIl.Emit(OpCodes.Ldarg_0);
ctorIl.Emit(OpCodes.Call, parentCtor);
// as above
z tymi liniami, mój kod działa teraz zgodnie z oczekiwaniami.
Więc moje pytania to:
- Dlaczego musimy jawnie wywołać konstruktora bazowy instancji pola?
- Czy jest uzasadnione użycie nie wywoływania podstawowego konstruktora?
- ... a jeśli nie, dlaczego CLR akceptuje to jako ważny program?
@PatrickHofman Najlepszy edit kiedykolwiek: P –
Konstruktor klasy podstawowej jest zawsze ** zawsze wywoływany. Jeśli nie napiszesz tego bezpośrednio w swoim kodzie C#, kompilator zrobi to za Ciebie. I * nie * zauważ, że zawsze jest jeden, System.Object ma konstruktora. Bardzo łatwe do zobaczenia dzięki ildasm.exe, narzędziu, z którego zawsze chcesz skorzystać, zanim zaczniesz generować własny MSIL. –
@HansPassant w języku C# jest, tak; w IL: nie tak dużo –