当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《为什么c#编译器在使用new()约束的泛型类型调用newin时会发出Activator.CreateInstance?》经验,为你挑选了2个好方法。

如果您有以下代码:

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

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

我有以下解决方法:

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

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

    private static Func _func = CreateFunc();
}

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

但是,为什么这个解决方案应该是必要的,这对我没有意义.



1> Jon Skeet..:

怀疑这是一个JITting问题.目前,JIT为所有引用类型参数重用相同的生成代码 - 因此一个Listvtable指向与之相同的机器代码List.如果new T()必须在JITted代码中解析每个调用,那将无效.

只是一个猜测,但它有一定的意义.

一个有趣的小点:在任何情况下都不会调用值类型的无参数构造函数(如果有的话)(这种情况很少见).有关详细信息,请参阅我最近的博文 我不知道是否有任何方法可以强制它在表达式树中.



2> JaredPar..:

这很可能是因为不清楚T是值类型还是引用类型.在非通用场景中创建这两种类型会产生非常不同的IL.面对这种模糊性,C#被迫使用通用的类型创建方法.Activator.CreateInstance符合要求.

快速实验似乎支持这一想法.如果键入以下代码并检查IL,它将使用initobj而不是CreateInstance,因为类型没有歧义.

static void Create()
    where T : struct
{
    var x = new T();
    Console.WriteLine(x.ToString());
}

将其切换为类和new()约束仍会强制激活Activator.CreateInstance.


我想紧接着的后续问题是"为什么没有适当的IL指令用于创建具有适当约束的泛型类型的实例?" 它不像他们从一开始就无法构建它:)
只是一个快速的说明,这不再是悲伤的事实.无论约束如何,Roslyn都会输出`Activator.CreateInstance`.
推荐阅读
雯颜哥_135
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有