14

If one wants to create a new instance of a generic, the new constraint needs to be defined, like so:

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

Is it possible, using reflection, to create an instance of T without the new constraint, like so (contains pseudocode):

public T SomeMethod<T>()
{
    if (T has a default constructor)
    {
        return a new instance of T;
    }
    else
    {
        return Factory<T>.CreateNew();
    }
}
4

3 回答 3

21

用于Activator.CreateInstance()此。有关如何使用此方法的更多信息,请参阅http://msdn.microsoft.com/en-us/library/system.activator.createinstance.aspx 。基本上,你要做的是:

var obj = (T)Activator.CreateInstance(typeof(T));

您可以使用以下方法验证它是否具有默认构造函数GetConstructors()

var constructors = typeof(T).GetConstructors();

如果你发现有零参数的构造函数,你可以使用该Activator.CreateInstance方法。否则,您使用该Factory<T>.CreateNew()方法。

编辑:

要直接查明是否存在不带任何参数的构造函数,可以使用以下检查:

if (typeof(T).GetConstructor(Type.EmptyTypes) != null)
{
    // ...
于 2013-06-26T06:47:08.307 回答
10

具有where T : new()约束的通用方法new T()通过调用Activator.CreateInstance<T>(). 关于这个方法的一个有趣的事情是它不包括约束,所以如果你愿意将检查推迟到运行时,只需使用:

public T SomeMethod<T>() {
    return Activator.CreateInstance<T>();
}

要么完全按照return new T() 应做的,要么会引发一个有意义的异常。因为它同时处理成功和失败的情况,所以进行任何额外的检查并没有真正的好处,除非你想做一些晦涩的事情,比如根本不使用构造函数(可以这样做)。

于 2013-06-26T06:55:41.930 回答
1

Marc Gravell 回答的最后一句话(强调我的)

...除非您想做一些晦涩的事情,例如根本不使用构造函数(可以这样做

从他的这个评论来看,有另一种方法可以实现同样的目标。我不太知道哪个性能更好,但老实说,我不在乎。如果您想知道,请点击该链接。那里作者展示了一种混合方式。

使用System.Runtime.Serialization.FormatterServices.GetUninitializedObject()(旧 MSDN 文档链接)。

public static T SomeMethod<T>()
{
    if (typeof(T) == typeof(string))
    {
        return default(T);
    }

    return (T)FormatterServices.GetUninitializedObject(typeof(T));
}

注意要特别注意string。没有它GetUninitializedObject()就会失败。这是来自 MSDN 关于在字符串上使用这种方法的内容:

它不会创建未初始化的字符串,因为创建不可变类型的空实例没有任何意义。

它没有说明它失败的原因,而是更多地说明了它为什么会失败。紧随其后的是另一个注释,如下所示:

您不能使用 GetUninitializedObject 方法来创建派生自ContextBoundObject类的类型的实例。

于 2018-07-18T17:38:26.537 回答