在C#中,方法声明后面的<T>是什么?

27
我是一名VB.Net程序员(因为我的雇主要求我这样做:P)。我在Java中成长,通常不会在有机会时阅读或编写C#代码。今天我遇到了一些我从未见过的语法,似乎无法理解。
在下面的方法声明中,< T > 代表什么?
static void Foo < T >(params T[] x)
我曾看到它与声明泛型集合和其他内容一起使用,但我无法弄清楚它对该方法有何作用。
如果有关系的话,我是在考虑一些C#脑筋急转弯时遇到它的。第六个脑筋急转弯包含整个代码片段。
4个回答

34
你所询问的是C#中泛型的概念。通过使用泛型,您可以将此方法用于所需的类型。
假设您需要创建一个将两个数字相加的函数。那么,您的函数应该是:
//For integer :
public int sum(int a, int b)
{ 
  return a + b;
}



//For floating point numbers :
public float sum( float a, float b)
{
  return a + b;
}

按照这个逻辑,如果你想要一个将两个双精度类型数字相加的函数,你需要再创建一个函数,以此类推。

注意:上面的代码在C#中不起作用,但为了方便解释概念而写的伪代码。如果你有可空类型或引用类型,它将可以在C#中工作,或者需要编写逻辑将值转换为主类型。

但是通过泛型的帮助,您可以替换所有这些函数并编写以下内容:

public T sum<T>(T a, T b)
{
  return a + b;
}

这将适用于所有数字类型,以及字符串。

更多细节请查看:http://www.codeproject.com/kb/books/EssentialCS20.aspx


5
对于代码示例和易于跟随的示例+1!清晰地展示了问题的理解以及原始作者的理解水平。 - Armstrongest
2
这个例子很容易理解,但是它不起作用。你不能添加两个通用类型 T 的变量。请参见:https://dev59.com/gXVD5IYBdhLWcg3wRpeX 解决方法是使用来自外部库的通用运算符:http://www.yoda.arachsys.com/csharp/miscutil/usage/genericoperators.html - Philip Daubmeier
感谢提供这些信息,我更深入地了解了C++模板。 - Pranay Rana

24

这定义了一个通用方法,它是C# 2.0中添加的泛型的一种形式。

方法签名应该是:

static void Foo<T>(params T[] x)
{ // ...

这允许你将任意数量的任何(特定)类型的参数传递到方法Foo中,并对该参数数组进行操作。它类似于通用类型的工作方式,只是范围仅限于该方法。 <T> 指定传递到方法中的参数类型,因此您可以像这样调用它:

Foo<MyClass>(myClassInstance, myClassInstance2, mySubclassInstance);

具体而言,它定义了方法中用于泛型类型的名称。 - Adam Robinson
2
我的理解是,在这段代码中,(params T[] x) 声明了该方法接受类型为 T 的任意数量的参数,并将它们存储在由 x 引用的数组中。如果我的理解正确,那么方法名后面的 <T> 在声明中起到了什么作用呢? - Drew
也许它允许调用者在描述传递的变量类型作为参数时更加详细。只要myClassInstance和myClassInstance2是相同的类型,我就可以使用一行代码Foo(myClassInstance, myClassInstance2)来调用Foo函数吗? - Drew
3
@Drew:在函数中,您需要声明要使用的类型。编译器不知道您使用的是什么类型,因为T[]并没有指定类型,而是通过<T>进行声明。作为函数的调用者,您可以设置类型。例如:Foo<int>(1, 2, 3);或者Foo<float>(1.0, 2.0, 3.0); - Philip Daubmeier
1
@Drew:就像变量声明一样,您可以使用任何名称。您还可以编写:static void Foo<Bar>(params Bar[] x) { }。这只是在字典中使用 TTKeyTValue 等约定俗成的用法。 - Philip Daubmeier
5
请注意,当编译器可以推断出类型时,调用函数时可以省略 <T>。例如,Foo(new Bar(), new Bar()) 等同于 Foo<Bar>(new Bar(), new Bar())。当传递具有共同基础类型或匿名方法的多个不同类型对象时,编译器不能确定应该使用哪种类型。 - Will Vousden

2
T是一个类型参数,在这种情况下可以是任何东西(可以指定约束,但这里没有约束)。如果没有这个特性,你就必须为你计划使用的每种类型声明方法:
static void Foo(params int[] x)    
static void Foo(params string[] x)    
static void Foo(params Customer[] x)    
etc...

更多关于泛型的信息可以在MSDN上找到:泛型介绍 (C#)

这是关于泛型类型的MSDN页面 http://msdn.microsoft.com/zh-cn/library/512aeb7t.aspx - Armstrongest

1
这是泛型方法的泛型类型参数。
一旦在调用方法时为T指定一个类型,.NET就可以根据该类型参数来确保类型安全。
static void Foo<T>(params T[] x) { }

将被称为:

string[] names = new string[] {"Foo", "Bar", "Baz"};

Foo<string>(names);

但这会导致编译器错误:

int[] nums = new int[] {1, 2, 3};

Foo<string>(nums); // nums is not string[]

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