如何初始化泛型参数类型 T?

27
简单问题:
如果你有一个字符串x,要对它进行初始化,只需执行以下操作之一:
string x = String.Empty;  

或者
string x = null;

关于泛型参数T呢?

我尝试过这样做:

void someMethod<T>(T y)
{
    T x = new T();  
    ...
}

生成错误:
无法创建变量类型“T”的实例,因为它没有“new()”约束


你为什么想要在不知道类型的位置执行它? - Amar
5个回答

44

您有两个选项:

您可以约束 T:通过在方法中添加 where T : new()。现在,您只能使用具有无参数默认构造函数的类型来使用 someMethod(请参见类型参数约束)。

或者您可以使用default(T)。对于引用类型,这将给出null。但是例如,对于整数值,这将给出0(请参见泛型代码中的默认关键字)。

这里是一个演示差异的基本控制台应用程序:

using System;

namespace Stackoverflow
{
    class Program
    {
        public static T SomeNewMethod<T>()
            where T : new()
        {
            return new T();
        }

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

        struct MyStruct { }

        class MyClass { }

        static void Main(string[] args)
        {
            RunWithNew();
            RunWithDefault();
        }

        private static void RunWithDefault()
        {
            MyStruct s = SomeDefaultMethod<MyStruct>();
            MyClass c = SomeDefaultMethod<MyClass>();
            int i = SomeDefaultMethod<int>();
            bool b = SomeDefaultMethod<bool>();

            Console.WriteLine("Default");
            Output(s, c, i, b);
        }

        private static void RunWithNew()
        {
            MyStruct s = SomeNewMethod<MyStruct>();
            MyClass c = SomeNewMethod<MyClass>();
            int i = SomeNewMethod<int>();
            bool b = SomeNewMethod<bool>();

            Console.WriteLine("New");
            Output(s, c, i, b);
        }

        private static void Output(MyStruct s, MyClass c, int i, bool b)
        {
            Console.WriteLine("s: " + s);
            Console.WriteLine("c: " + c);
            Console.WriteLine("i: " + i);
            Console.WriteLine("b: " + b);
        }

    }
}

它会产生以下输出:
New
s: Stackoverflow.Program+MyStruct
c: Stackoverflow.Program+MyClass
i: 0
b: False
Default
s: Stackoverflow.Program+MyStruct
c:
i: 0
b: False

1
此外,如果您有 where T : struct,那么 T t = new T(); 是允许的,并且产生与 default(T) 相同的值。如果您有约束条件 where U : class,那么 U u = null; 是允许的,并且等同于 default(U)。约束条件 where U : new() 可以与 class 结合使用,但不能与 struct 结合使用。 - Jeppe Stig Nielsen
多年后...如果您的Type是数字原始类型,那么这将很好地工作。它们有默认构造函数可以生成零默认值。 - O. Jones

14
使用 default 关键字。
T x = default(T);

参见:C#编程指南:泛型代码中的默认关键字

给定一个参数化类型T的变量t,只有当T是引用类型时语句t = null才有效,而t = 0仅适用于数值值类型而不适用于结构体。解决方案是使用default关键字,它将返回null(对于引用类型)或零(对于数值值类型)。对于结构体,它将返回每个成员初始化为零或null,具体取决于它们是值类型还是引用类型。


9
您需要为类型参数 T 添加一个 new 约束。
void someMethod<T>(T y) where T : new()
{
    T x = new T();  
    ...
}

然而,这仅适用于具有默认构造函数的类型。

Twhere 子句是一个泛型类型约束。在这种情况下,它要求此方法应用于的任何类型 T 必须具有公共无参构造函数。


添加new()约束。很简单 :) - Rawling
@Lee 默认和 无参数 :D - Matías Fidemraizer
请问您能够解释一下where:语法背后发生的事情吗? - JavaSa
@JavaSa 这是一个不错的起点 - Rawling
@JavaSa - 我已经添加了一个解释。 - Lee

5
如果您确实需要一个 T 类型的实例,而不是引用类型的默认空值,请使用以下代码:
Activator.CreateInstance()

0

您可以使用default构造函数将其设置为该类型的默认值。

default关键字允许您告诉编译器,在编译时应使用此变量的默认值。如果提供的类型参数是数字值(例如,int、long、decimal),则默认值为零。如果提供的类型参数是引用类型,则默认值为null。如果提供的类型参数是结构体,则结构体的默认值由将结构体的每个成员字段初始化为数字类型的零或引用类型的null来确定。

使用以下代码:

T data = default(T);

有关详细信息,请阅读:将泛型变量初始化为其默认值


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