Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Explicit constructor call in C#

So, today I reflected an arbitary .NET assembly using ILSpy + dotPeek to gain deeper insight about how IL code works when I stumbled upon this weird part (dummy example):

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

As far as I can see, the derived class doesn't call the base constructor in the first place, but instead does something with onlyOneInstance and then calls be base constructor.

My question is: Is it possible to call the base constructor explicitly in C# after some work has been done? Or is this only possible in IL? I know it's being easily done in e.g. Java using super(), however I've never seen it in .NET.


EDIT

I just had a talk with my boss and he's okay with posting some real world code of the library (it's one of our companys internal):

**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>)
like image 585
xvdiff Avatar asked Feb 12 '15 21:02

xvdiff


People also ask

What is explicit constructor call?

Explicit Constructor Chaining using this() or super() Explicit use of the this() or super() keywords allows you to call a non-default constructor. To call a non-args default constructor or an overloaded constructor from within the same class, use the this() keyword.

What do you mean by implicit and explicit call of constructor in C++?

A default constructor is one which takes no parameters, an implicit call is when you directly call the constructor.


3 Answers

You can do this:

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

    {
    }
}

In other words, you definitely can run code prior to the base constructor as part of constructing the parameters passed to it. In this case, we're constructing an array to pass to the base class. You can also call static methods, as recursive mentions.


I missed the null check. Apparently they want to preserve the null passing case rather than an array containing null. That would be the equivalent of :

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

    {
    }
}
like image 130
Dan Bryant Avatar answered Oct 16 '22 17:10

Dan Bryant


One way something like this might happen is field initializer logic.

Another way you can kind of achieve it is calling static methods for base constructor argument values.

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;
    }
}
like image 40
recursive Avatar answered Oct 16 '22 17:10

recursive


Complementing the other answers:

The CLR allows you to run arbitrary stuff before calling the base class ctor. The CLR enforces that you do call the base class ctor in all possible paths through the method exactly once. I recently experimented with that using peverify.

C# enforces other restrictions as you have noticed. If a different language was used to compile this assembly then only the CLR rules apply. And even those do not apply for SkipVerification code which, I believe, is almost all code that runs nowadays.

like image 20
usr Avatar answered Oct 16 '22 18:10

usr