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

本文关键字:调用 构造函数 MSIL 我们 为什么 | 更新日期: 2023-09-27 18:21:28

我只是花了几个小时被一个我认为不应该有的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 接受它作为有效程序?

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

  1. 因为它不是自动的,并且它允许编译器和 IL 代码决定何时以及是否调用基构造函数
  2. 好吧,您实际上可以在不使用任何构造函数的情况下实例化类型......边缘情况,当然;但允许
  3. 因为它是允许的

请注意,您实际上可以在单个方法中发出一个简单的构造函数(包括基调用(:

typeBuilder.DefineDefaultConstructor();