为什么我们需要在MSIL中显式调用父构造函数?

时间:2014-09-11 13:11:45

标签: c# cil reflection.emit

我只是花了好几个小时被一个NullReferenceException弄糊涂了,我认为那里不应该是一个人。我正在构建一个类似的类:

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

,其中

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

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

基本上我的IL如下:

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);

我终于认为必须是bar没有被实例化。我在C#中构建了我的类并编译它,发现唯一的区别是以下应该高于上面的IL:

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

使用这些行,我的代码现在可以正常工作了。

所以我的问题是:

  1. 为什么我们需要显式调用基础构造函数来实例化字段?
  2. 是否合法使用不调用基础构造函数?
  3. ...如果没有,为什么CLR接受它作为有效的程序?

1 个答案:

答案 0 :(得分:6)

  1. 因为它不是自动的,它允许编译器和IL代码决定何时 来调用基础构造函数
  2. 好吧,你实际上可以在不使用任何构造函数的情况下实例化类型...边缘情况,当然;但允许
  3. 因为允许
  4. 请注意,您实际上可以在单个方法中发出一个简单的构造函数(包括基本调用):

    typeBuilder.DefineDefaultConstructor();