为什么在没有new()泛型类型约束的情况下允许Activator.CreateInstance <t>()?

时间:2016-09-12 05:58:24

标签: c# .net generics activator type-constraints

在下面显示的示例代码中,“CompileError”方法将无法编译,因为它需要where T : new()约束,如CreateWithNew()方法所示。但是,CreateWithActivator<T>()方法在没有约束的情况下编译就好了。

public class GenericTests
{
    public T CompileError<T>() // compile error CS0304
    {
        return new T();
    }

    public T CreateWithNew<T>() where T : new() // builds ok
    {
        return new T();
    }

    public T CreateWithActivator<T>() // builds ok
    {
        return Activator.CreateInstance<T>();
    }
}

这是为什么?

根据引用https://stackoverflow.com/a/1649108/531971MSDN documentationthis question,使用{{1}实际上实现了实现中的new T()表达式}。所以我不明白为什么调用Activator.CreateInstance<T>()要求以使用new T()时可以省略的方式约束泛型类型。

或者,以相反的方式提出问题:Activator.CreateInstance<T>()约束的重点是什么,如果在没有约束的情况下在通用方法中创建where T : new()的实例很容易,可以直接使用完全相同的底层基础设施?

3 个答案:

答案 0 :(得分:12)

ActivatorT()之间存在概念差异:

  • Activator.CreateInstance<T> - 我想使用默认构造函数 创建T的新实例,如果没有Exception则抛出CreateInstance<T>()一个 (因为发生了一些非常错误的事情,我想自己处理它/扔掉它)

    • 旁注:请注意as MSDN says

        

      通常,应用程序代码中的Type泛型方法没有用处,因为必须在编译时知道该类型。如果在编译时已知类型,则可以使用正常的实例化语法。

      因为通常你会想要在编译时CreateInstance<T>()已知Activator.CreateInstance<T>时使用构造函数(T() uses RuntimeTypeHandle.CreateInstance这更慢 [这就是为什么T本身不需要约束] )。

  • Exceptions - 我想调用T()的空构造函数,据说就像标准的构造函数调用一样。

您不希望“标准”构造函数调用失败,因为“没有找到这样的构造函数”,因此,编译器希望您约束有之一。

不止于此; 您应该首选编译时间误差超过T

main(void){ int B[4][3] = {{1,0,0}, {1,0,1},{1,1,0},{1,1,1}}; int Y[1][4] = {{1}, {1}, {1}, {0}}; } 内部使用与“我只想要{{1}}”的默认实例的平均情况无关的反射实现{当然,如果你内部实现很重要关心表现/等......)

答案 1 :(得分:2)

这只是糖。如果可以的话,自控糖。例如,您可以通过反射调用几乎任何类型的任何方法(在某些情况下甚至没有实例!),但这是不对的,你不同意吗?您的代码在某些时候将变得无法维护,并且执行时会弹出许多错误,这非常糟糕。所以,如果你可以在执行前控制自己 - 就这样做吧。

Constraint将帮助您在编译时理解它。

答案 2 :(得分:1)

Activator.CreateInstance<T>()方法暴露给用户代码,以允许泛型类可能以不同方式使用,其中一些方法需要类型参数满足某些约束,而其中一些不满足。例如,类Foo<T>可能支持以下任何使用模式:

  1. 客户端代码提供的函数返回新的T

  2. 客户端代码遵循默认函数,该函数使用其默认构造函数创建新的T

  3. 客户端代码避免使用类的任何要求创建T的新实例的功能。

  4. 模式#1和#3应该可以与任何T一起使用,而#2应该只适用于具有无参数构造函数的类型。让Activator.CreateInstance<T>()为无约束的T编译,并为恰好具有无参数构造函数的类型T工作,使得代码支持所有三种使用模式变得容易。如果Activator.CreateInstance<T>有一个new约束,那么将它与没有一个参数的泛型类型参数一起使用会非常尴尬。