为什么当使用new()约束的泛型类型调用new时,c#编译器发出Activator.CreateInstance?

为什么当使用new()约束的泛型类型调用new时,c#编译器发出Activator.CreateInstance?

问题描述:

当您有如下代码:

static T GenericConstruct<T>() where T : new()
{
    return new T();
}

C#编译器坚持发出对Activator.CreateInstance的调用,比本地构造函数慢。

The C# compiler insists on emitting a call to Activator.CreateInstance, which is considerably slower than a native constructor.

我有以下解决方法:

public static class ParameterlessConstructor<T>
    where T : new()
{
    public static T Create()
    {
        return _func();
    }

    private static Func<T> CreateFunc()
    {
        return Expression.Lambda<Func<T>>( Expression.New( typeof( T ) ) ).Compile();
    }

    private static Func<T> _func = CreateFunc();
}

// Example:
// Foo foo = ParameterlessConstructor<Foo>.Create();

但对我来说,为什么这种解决方法是必要的。

But it doesn't make sense to me why this workaround should be necessary.

可疑这是一个JITTING问题。目前,JIT对所有引用类型参数重用相同的生成代码 - 因此 List< string> 的vtable指向与 List< Stream> 。如果每个 new T()调用必须在JIT代码中解决,那么这将不会工作。

I suspect it's a JITting problem. Currently, the JIT reuses the same generated code for all reference type arguments - so a List<string>'s vtable points to the same machine code as that of List<Stream>. That wouldn't work if each new T() call had to be resolved in the JITted code.

一个有趣的小点:既不在 case 一个值类型的无参构造器被调用,如果有一个(这是极少见的)。请参阅我最近的博文详情。我不知道是否有任何方式强迫它在表达式树。

One interesting little point: in neither case does the parameterless constructor of a value type get called, if there is one (which is vanishingly rare). See my recent blog post for details. I don't know whether there's any way of forcing it in expression trees.