Явный вызов конструктора в C#

Итак, сегодня я отразил сборку arbitary .NET с помощью ILSpy + dotPeek, чтобы получить более глубокое представление о том, как работает 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? Я знаю, что это легко сделать, например, Java, используя super(), однако я никогда не видел его .Сеть.


редактировать

у меня только что был разговор с моим боссом, и он в порядке с публикацией некоторого реального кода библиотеки (это одна из наших внутренних компаний):

**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 ответов


вы можете сделать это:

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)

    {
    }
}

один из способов, как это может произойти, это логика инициализатора поля.

другой способ, которым вы можете добиться этого, - это вызов статических методов для значений аргументов базового конструктора.

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

дополняя другие ответы:

среда CLR позволяет запускать произвольные вещи перед вызовом базового класса ctor. Среда CLR обеспечивает вызов базового класса ctor во всех возможных путях через метод ровно один раз. Недавно я экспериментировал с этим, используя peverify.

C# применяет другие ограничения, как вы заметили. Если для компиляции этой сборки использовался другой язык, применяются только правила среды CLR. И даже те не претендуют на SkipVerification код, который, я считаю, почти весь код, который работает в настоящее время.