Явный вызов конструктора в 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
код, который, я считаю, почти весь код, который работает в настоящее время.