在泛型中,返回一个新的实例而不是空实例。

4

我有一个从独立存储中提取对象的类。如果它无法找到所需的对象,则返回default(T),因为它们是引用类型,所以会返回null。如果返回的值为null,我会在调用者中进行简单的检查并分配一个新实例,但我更喜欢在存储逻辑中完成此操作。

我的问题是,是否有一种方法可以返回具有默认空构造函数的新T对象?


5个回答

15

一个选项是使用约束“new”:

http://msdn.microsoft.com/zh-cn/library/sd2w2ew5(v=vs.80).aspx

示例代码如下:

public T GetNewItem()
    where T: new()
{
    return new T();
}

但是有这个限制意味着你不能使用没有默认构造函数的类型。因此,您可以考虑使用System.Activator.CreateInstance,但请记住它可能会抛出异常:

T createInstance<T>()
{
    try
    {
        return System.Activator.CreateInstance<T>();
    }
    catch (MissingMethodException exc)
    {
        return default(T);
    }
}

因此,在初始化过程中了解所给类型是否支持这一点可能是个好主意,以下是一种实现方式:

T createInstance<T>()
{
    System.Reflection.ConstructorInfo constructor = (typeof(T)).GetConstructor(System.Type.EmptyTypes);
    if (ReferenceEquals(constructor, null))
    {
        //there is no default constructor
        return default(T);
    }
    else
    {
        //there is a default constructor
        //you can invoke it like so:
        return (T)constructor.Invoke(new object[0]);
        //return constructor.Invoke(new object[0]) as T; //If T is class
    }
}

在此期间,为什么不获取一个创建实例的委托呢?
Func<T> getConstructor<T>()
{
    System.Reflection.ConstructorInfo constructor = (typeof(T)).GetConstructor(System.Type.EmptyTypes);
    if (ReferenceEquals(constructor, null))
    {
        return () => { return default(T); };
    }
    else
    {
        return () => { return (T)constructor.Invoke(new object[0]); };
    }
}

一个使用它的例子(在LinqPad中编译):
void Main()
{
    Console.WriteLine(getConstructor<object>()());
    Console.WriteLine(getConstructor<int>()());
    Console.WriteLine(getConstructor<string>()());
    Console.WriteLine(getConstructor<decimal>()());
    Console.WriteLine(getConstructor<DateTime>()());
    Console.WriteLine(getConstructor<int?>()());
}

输出结果为:
System.Object
0
null
0
01/01/0001 12:00:00 a.m.
null

字符串(string)是一个特殊的情况,它是引用类型,因此可以为null,并且没有公共默认构造函数,所以在这里你得到的是null而不是String.Empty。可空类型也会返回null。


3

您可以为类型参数添加约束,但这将排除任何不支持空参数构造函数的类被用作类型参数。

public class Foo<T> where T : new()
{
    // Now you can say T blah = new T();
}

你也可以调用 Activator.CreateInstance<T>(),但如果类型没有正确的构造函数,则会抛出异常。
我认为你最好记录下你的方法返回 null 如果找不到对象,并让调用代码处理适当的情况。它将处于最佳位置,知道如何继续进行。

2

在你的泛型方法中添加new()约束:

public T Create<T>() where T: class, new()
{
  return new T();
}

1

这个是有效的:

使用 System;

public class Test
{
    static T CreateT<T>(bool _new) where T: new()
    {
        if (_new) return new T(); else return default(T);
    }
    public static void Main()
    {
        var o = CreateT<object>(true);
    }
}

0

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