用通俗易懂的语言解释C#中的泛型是什么?

4

重复的问题:C#中的"< >"语法是什么


实际上我想知道“何时应该使用泛型以及为什么要使用它?”

它的必要性是什么?


这真的值得-2分吗?我怀疑。+1 - Ian G
唯一愚蠢的问题是你没有问出来的问题。我给你点赞,这是一个很好的基础问题。如果它是“什么是< >”的重复,那么你已经知道答案了。 - Jim C
@Jim:发这个问题并没有错,但是答案已经在重复的帖子里了,所以保留这个问题也没有意义,对吧? - Brann
@Brann - 如果问题的措辞不同,那么我认为它应该保持开放状态。仅仅因为两个问题有相同的答案,并不意味着它们是同一个问题。同时,谷歌搜索引擎带我来到了这个问题而不是另一个问题。 - Paul Rowland
6个回答

4

泛型是 C# 中在编译时确保类型安全的一种方式。

例子 - 泛型之前:

class Person 
{
 string name;
 string lastname;
 public Person(string _name )  { this.name = _name; }
}

class ClientCode
{
   public static void Main()
   {
         //create a list of person
         ArrayList personList = new ArrayList();
         Person p1 = new Person("John");
         Person p2 = new Person("Ram");
         personList.Add(p1);
         personList.Add(p2);
         // BUT, someone can do something like:
         // ArrayList does not stop adding another type of object into it
         object q = new object();
         personList.Add(q);
         // while accessing personlist
         foreach(object obj in personlist)
         {
            Person p = obj as Person;
            // do something, for person
            // But it will fail for last item in list 'q' since its is not person.
         }
   }
}

示例-后生成:

class ClientCode
{
   public static void Main()
   {
         //create a list of person
         List<Person> personList = new List<Person>();
         Person p1 = new Person("John");
         Person p2 = new Person("Ram");
         personList.Add(p1);
         personList.Add(p2);
         // Someone can not add any other object then Person into personlist
         object q = new object();
         personList.Add(q); // Compile Error.
         // while accessing personlist, No NEED for TYPE Casting
         foreach(Person obj in personlist)
         {
            // do something, for person
         }
   }
}

3

泛型让你可以像参数化值一样,将代码参数化为类型。这可能并不能完全解释清楚,所以让我们一步步来看:

想象一下你想要一个程序来打印“我喜欢兔子”。你可以写出以下代码:

static void Main()
{
    ILikeBunnies();
}

void ILikeBunnies() { Console.WriteLine("I like bunnies"); }

一切都很好。但是你也喜欢奶酪,所以现在你有:

static void Main()
{
    ILikeBunnies();
    ILikeCheese();
}

void ILikeBunnies() { Console.WriteLine("I like bunnies"); }
void ILikeCheese()  { Console.WriteLine("I like cheese"); }

您会发现两个函数几乎相同。您希望重复使用 同一个 函数,但为所需的参数提供不同的

static void Main()
{
    ILike("bunnies");
    ILike("cheese");
}

void ILike(string what) { Console.WriteLine("I like " + what); }

这就是函数参数的作用:它们让您可以重复使用相同的代码,但使用不同的值。
泛型也是如此,但您传递的不是不同的值,而是 类型。假设您有一些需要将两个字符串捆绑到数组中的代码:
static void Main()
{
    string[] s = Pair("a", "b");
}

string[] Pair(string a, string b) { return new string[] { a, b }; }

好的。后来你发现自己还需要将整数捆绑成一个数组:
static void Main()
{
    string[] s = Pair("a", "b");
    int[]    i = Pair(1, 2);
}

string[] Pair(string a, string b) { return new string[] { a, b }; }
int[]    Pair(int    a, int    b) { return new int[]    { a, b }; }

就像之前一样,我们可以看到那里有很多冗余。我们需要一个函数,返回一对任何东西以及一种方法来传递我们想要一对的类型。这就是泛型的用途:

static void Main()
{
    string[] s = Pair<string>("a", "b");
    int[]    i = Pair<int>(1, 2);
}

T[] Pair<T>(T a, T b) { return new T[] { a, b }; }

角括号让您以与括号传递值相同的方式向函数传递类型。这里的“T”是类型参数的名称,就像上面的“what”是值参数一样。函数中出现的任何T都将被替换为您传递的实际类型(在示例中为string和int)。
除此之外,泛型还有很多其他功能,但基本思想是:泛型让您以与参数传递值相同的方式向函数(和类)传递类型。

在你的最后一个例子中,T[] Triple... 应该是 T[] Pair<T>( T a, T b ) { return new T[] { a, b }; }。 - Metro Smurf
我知道这个问题很老了,但是对于任何试图使用它的人来说,他们需要声明该泛型方法为静态的:static T[] Pair<T>(T a, T b)等等...否则它将无法编译。 - CodeChops

1

泛型基本上消除了将对象转换为其基本类型的需要。

例如,如果您想在列表中存储一组Foos。

您以前必须创建自己的FooList或将项目强制转换为对象。

所有这些都需要花费您的时间和编译器。

使用泛型,您只需设置List,它会检查您的类型并加速程序。 (无装箱和拆箱)


0
假设你自己是一个算法,可以对可以成对比较的任何对象进行排序(纸牌、CD、名片等)。只要你能够比较它们,你实际上并不关心这些具体的对象是什么。因此,你成为了一个通用的(这里的“通用”是广义的术语,而不是C#中的意义)算法。
.NET中的泛型有助于促进这种特定类型的行为,不仅在算法(通用函数)方面,还在通用类型(类、结构、委托、接口)方面。

我知道什么是泛型...但那只是让我更困惑 :( - Richard Walton

0
只是为了补充其他人会告诉你的,更实际地说,尝试使用 ArrayListSystem.Array 对象做一些事情,然后再尝试使用 List<T>,你就可以立即看到泛型如何让你编写更易读的代码,并且更快地编写它。

0

我很久以前写过一篇博客,链接在这里。当时我正在处理XML,我想要一个帮助类,可以根据XPath获取一个XmlElement或者XmlAttribute,并让我方便地操作它。这是一个非常好的简单示例,当时泛型在C#中还比较新。


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