C#中的显式构造函数调用

时间:2015-02-12 21:56:22

标签: c# .net inheritance reflection il

所以,今天我反映了一个使用ILSpy + dotPeek的仲裁.NET程序集,以便在我偶然发现这个奇怪的部分(虚拟示例)时更深入地了解IL代码的工作原理:

public class SomeBaseClass {
    public SomeBaseClass(SomeType[] iExpectACollection) {
        ...
    }
}

public class SomeDerivedClass {
    public SomeDerivedClass(SomeType onlyOneInstance) {
        SomeType[] collection;
        if(onlyOneInstance != null)
            collection = new SomeType[] { onlyOneInstance };
        base.\u002Ector(collection);
    }
}

据我所知,派生类首先没有调用基础构造函数,而是使用onlyOneInstance然后调用基本构造函数。

我的问题是:在完成一些工作后,是否可以在C#中显式调用基础构造函数?或者这只能在IL中使用?我知道它很容易在例如使用super()的Java,但我从未在.NET中看到它。


修改

我刚与老板谈过话,他发布了一些真实世界的图书馆代码(它是我们公司内部的一个代码),这是好的:

**IL PART**
.method public hidebysig specialname rtspecialname 
instance void .ctor (
    string contextId,
    class MyComp.NetStack.BufferManager bufferManager,
    class MyComp.NetStack.TcpChannelQuotas quotas,
    class [System]System.Security.Cryptography.X509Certificates.X509Certificate2 clientCertificate,
    class [System]System.Security.Cryptography.X509Certificates.X509Certificate2[] clientCertificateChain,
    class [System]System.Security.Cryptography.X509Certificates.X509Certificate2 serverCertificate,
    class MyComp.NetStack.EndpointDescription endpoint,
    class MyComp.NetStack.ApplicationThreadPool threadPool
) cil managed 
{
// Method begins at RVA 0x648e0
// Code size 263 (0x107)
.maxstack 10
.locals init (
    [0] class MyComp.NetStack.EndpointDescription[]
)

IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: ldarg.2
IL_0003: ldarg.3
IL_0004: ldarg.s serverCertificate
IL_0006: ldarg.s clientCertificateChain
IL_0008: ldarg.s endpoint
IL_000a: brtrue.s IL_000f

IL_000c: ldnull
IL_000d: br.s IL_0021

IL_000f: ldc.i4.1
IL_0010: newarr MyComp.NetStack.EndpointDescription
IL_0015: stloc.0
IL_0016: ldloc.0
IL_0017: ldc.i4.0
IL_0018: ldarg.s endpoint
IL_001a: stelem.ref
IL_001b: ldloc.0
IL_001c: newobj instance void MyComp.NetStack.EndpointDescriptionCollection::.ctor(class [mscorlib]System.Collections.Generic.IEnumerable`1<class MyComp.NetStack.EndpointDescription>)

3 个答案:

答案 0 :(得分:4)

你可以这样做:

public class SomeDerivedClass : SomeBaseClass {
    public SomeDerivedClass(SomeType onlyOneInstance)
        : base(new[] { onlyOneInstance})

    {
    }
}

换句话说,您肯定可以在基础构造函数之前运行代码,作为构造传递给它的参数的一部分。在这种情况下,我们正在构造一个数组以传递给基类。你也可以调用静态方法,作为递归提及。


我错过了空检查。显然,他们希望保留null传递大小写而不是包含null的数组。这相当于:

public class SomeDerivedClass : SomeBaseClass {
    public SomeDerivedClass(SomeType onlyOneInstance)
        : base(onlyOneInstance != null ? new [] { onlyOneInstance} : null)

    {
    }
}

答案 1 :(得分:2)

可能发生这种情况的一种方法是字段初始化逻辑。

另一种可以实现它的方法是为基础构造函数参数值调用静态方法。

class Base {
    public Base(object value) { 
        Console.WriteLine ("Base constructor");
    }
}

class Child : Base {
    public Child() : base(DoWorkBeforeBaseConstructor()) { }

    private static object DoWorkBeforeBaseConstructor() {
        Console.WriteLine ("doing work");
        return null;
    }
}

答案 2 :(得分:2)

补充其他答案:

CLR允许您在调用基类ctor之前运行任意内容。 CLR强制您通过该方法在所有可能的路径中调用基类ctor一次。我最近使用peverify进行了实验。

C#强制执行其他限制,因为您已经注意到了。如果使用其他语言编译此程序集,则仅应用CLR规则。甚至那些代码也不适用于SkipVerification代码,我相信这些代码几乎都是现在运行的代码。