创建一个没有新约束的T的新实例

本文关键字:约束 新实例 实例 一个 创建 新约束 | 更新日期: 2023-09-27 18:20:00

如果想要创建泛型的新实例,则需要定义新约束,如下所示:

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

有没有可能,使用反射,在没有新约束的情况下创建一个T的实例,比如这样(包含伪代码):

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

创建一个没有新约束的T的新实例

为此使用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)
{
    // ...
具有where T : new()约束的泛型方法通过调用Activator.CreateInstance<T>()来实现new T()调用。这个方法的一个有趣之处在于,它不包括约束,所以如果您愿意将检查推迟到运行时,只需使用:
public T SomeMethod<T>() {
    return Activator.CreateInstance<T>();
}

这将执行与return new T()完全相同的操作,或者将引发有意义的异常。因为它同时处理成功和失败的情况,所以做任何额外的检查都没有真正的好处,除非你想做一些模糊的事情,比如根本不使用构造函数(这是可以做到的)。

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类的类型的。