Activator.CreateInstance<T>与new的区别

39

以下两种方式创建对象有什么区别吗?

Student s1 = Activator.CreateInstance<Student>();
Student s1 = new Student();
  • 构造函数的调用方式和初始化内存的方式有什么区别吗?
  • 据我理解,第一种方法看起来完全是多余的。如果程序员在设计时知道数据类型,他将使用第二种方法。

相关链接:https://dev59.com/pWw15IYBdhLWcg3wfbzi,https://dev59.com/Dm025IYBdhLWcg3wVkcR - nawfal
5个回答

18

这个 "Activator.CreateInstance" 方法的重载是由编译器使用的,用于通过泛型来实现类型参数指定的类型的实例化。

假设你有以下方法:

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

编译器将把"return new T();"转换为调用"CreateInstance"。
一般来说,在应用程序代码中没有使用CreateInstance的必要,因为类型必须在编译时已知。如果类型在编译时已知,则可以使用正常的实例化语法(C#中的new运算符,Visual Basic中的New,C++中的gcnew)。
更多信息:http://msdn.microsoft.com/en-us/library/0hcyx2kd.aspx

19
在编译时,数据类型未知是非常普遍的。在分离合同(接口)和实现时非常有用。 - Thorarin
1
没有“CreateInstance”,编写反序列化代码将非常困难! - Gabe
3
我认为最后一段话完全错误。在配置中使用类型名并需要实例化它是很常见的。我猜你特别指的是泛型重载(在问题中使用),它需要在编译时知道具体类型。 - Chad Schouggins
2
@ChadSchouggins 是的,我是指与泛型相关的内容。 - Chris Pietschmann

9
我不认为Activator.CreateInstance()是多余的。如果您知道类型,那么确实只需要使用new。然而,在需要从插件框架动态加载未知类型或者从字符串(例如设置文件)中解析类型的情况下,它非常有用。至于两者之间的区别,调用new T()Activator.CreateInstance<T>()在内部没有真正的区别,就像Andrew Hare已经指出的那样。编辑:不要紧,我已经混淆了通常更常用的 CreateInstance(Type type)

5

一个主要的区别是

Student s1 = new Student();

如果Student没有默认构造函数,则无法编译,而…
Student s1 = Activator.CreateInstance<Student>();

即使Student没有默认构造函数也会编译。(程序将编译并让你运行,但如果没有匹配的构造函数,你将得到一个异常。而如果构造函数不存在,则构造函数调用甚至不能编译。)
同样地,CreateInstance调用是对类的隐式使用,因此例如Resharper将不知道你正在实例化它,并可能告诉你该类从未被实例化。
正如其他答案中所提到的,CreateInstance调用还允许使用泛型类型参数:
T s1 = Activator.CreateInstance<T>();

虽然使用 new 类型约束可能更好,因为它可以在编译时确保实际上存在要调用的构造函数。

但是,Activator.CreateInstance(Type, ...) 重载要更加实用。


你确定吗?如果没有默认构造函数,它会调用哪个构造函数?它会向那个构造函数传递什么参数? - Zar Shardan
1
@ZarShardan 它会抛出一个异常。我的意思是它仍然可以编译通过;也就是说,你会得到一个运行时错误而不是编译器错误。(编译器错误更可取。) - Dave Cousineau

5

从性能角度来看,调用new更好。CreateInstance可能使用反射,这会很慢。
如果您在设计时知道类型,请使用new,即使两个调用完全相同(它们并不相同!)为什么要让代码变得过于复杂呢?

仅在您在设计时不知道T的类型且需要运行时解析类型时使用Activator.CreateInstance


是的,它使用反射,因此应该优先选择new T()而不是Activator.CreateInstance<T>()来源 - Shimmy Weitzhandler
@Shimmy,你的链接现在已经失效了,我试图修复它,但无法使其正常工作,你能否重新找到它或在其他地方找到相关信息?(我知道这已经过去8年了lol) - ForceMagic
1
这是一个新的更好的版本。 - Shimmy Weitzhandler

3
不,Activator.CreateInstance<T>只是在内部调用默认构造函数。你的示例之间唯一的区别是多了一个CreateInstance<T>方法调用。
来自Activator.CreateInstance<T>
创建指定泛型类型参数所指定类型的实例,使用无参构造函数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接