4

Given this code:

public class Test
{
    public T Get1<T>()
    {
        return Activator.CreateInstance<T>();
    }

    public T Get2<T>() where T : new()
    {
        return new T();
    }    
}

both methods produce exactly the same method body making use of System.Activator, namely:

.method public hidebysig instance !!T Get1<T> () cil managed 
{
    .maxstack 8

    call !!0 [mscorlib]System.Activator::CreateInstance<!!T>()
    ret
}

.method public hidebysig instance !!T Get2<.ctor T> () cil managed 
{
    .maxstack 8

    call !!0 [mscorlib]System.Activator::CreateInstance<!!T>()
    ret
}

Why does code using the new() constraint not compile to the fictional code below?

.method public hidebysig instance !!T Get2<.ctor T> () cil managed
{
    .maxstack 1

    newobj instance void !!0::.ctor()
    ret
}

Does not the constraint <.ctor T> mean that there has to be a parameterless constructor on the type T, therefore should not it be okay to just call it as shown above?


Aforementioned behavior occurs when compiled for .NET Framework 4.8 as well as .NET Core (x64) and with the latest (23 Sep 2019) Roslyn compiler.

Thomas Flinkow
  • 4,845
  • 5
  • 29
  • 65
  • 1
    In particular I´d expect the call with `new`-constraint not to rely on reflection. Strange, indeed. – MakePeaceGreatAgain Sep 26 '19 at 07:41
  • 1
    A more interesting question would be "does it matter" or is it optimized away by the compiler? CreateInstance's [source](https://github.com/dotnet/corert/blob/c43e3a05af142a17bf238a53baaebf634a9c7280/src/System.Private.CoreLib/shared/System/Activator.RuntimeType.cs#L142) shows it calls the runtime method [CreateInstanceDefaultCtor](https://github.com/dotnet/coreclr/blob/5b1c001bc0fb5bb1ce035c02ec275763f66defc8/src/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs#L3981) on the type itself. – Panagiotis Kanavos Sep 26 '19 at 07:54
  • 1
    @HimBromBeere It's actually pretty simple; all of the reifications of the generic type have the same x64 assembly for reference types. If you wanted to do `new T` for all possible T's, each T would need its own x64 code for the method containing the constructor. That has significant memory impact, especially for anonymous types which were one of the big reasons for introducing generics (for LINQ), and complicates many things. The costs of `Activator.CreateInstance` are usually negligible, and if they aren't, you can easily work around it with a simple delegate. – Luaan Sep 26 '19 at 10:31

0 Answers0