来个入门的,不说任何抽象概念,就拿 C# 里最常见的 List<T> 举个例子吧。
我们先假设世界上没有泛型这个概念,你就知道有 类型 这个玩意是啥意思就行。
你现在有一个学生类型,大概就长下面这样:
public class 学生类型
{
public string 名字 { get; set; }
}
上面的没有问题吧,你们老师让你写段程序,要求是接受输入3个学生的名字,输入完了把名字全部打印出来,你一阵噼里啪啦,代码就写好了,大概长这样
using System;
using System.Collections;
namespace ConsoleApp
{
public class 学生类型
{
public string 名字 { get; set; }
}
class Program
{
//程序入口,我猜你应该知道这个吧
static void Main(string[] args)
{
//ArrayList 就是个箱子,可以往里面装东西
ArrayList 箱子 = new ArrayList();
for (int i = 0; i < 3; i++)
{
Console.WriteLine("你给我一个学生的名字吧:");
//看看用户输入啥名字
string 输入 = Console.ReadLine();
//如果输入了名字,新建一个学生,然后把把刚才输入的名字给放到这个学生的名字属性里
学生类型 学生 = new 学生类型 { 名字 = 输入 };
//把刚才那个学生装到箱子里备用
箱子.Add(学生);
}
for(int i = 0; i < 箱子.Count; i++)
{
//把箱子里面的东西取出去,然后把它变成学生类型的玩意
学生类型 学生 = 箱子[i] as 学生类型;
Console.WriteLine(学生.名字);
}
}
}
}
写好了,你运行起来,没有问题
好了总结时间到,我们盘算一下,你在前面弄出一个箱子,如下
ArrayList 箱子 =new ArrayList();
可这个箱子外面什么都没有写,别人都不知道你这个箱子里装的什么东西,只有你知道里面放的是学生,所以你每次都要这样弄(as)一下别人才知道箱子取出来的是学生,如下
学生类型 学生 = 箱子[i] as 学生类型;
所以干脆把事情做漂亮点,在箱子外面贴个标签,告诉别人里面装的是学生不就完了?稍微改一下,我这里找了一个可以贴标签的箱子,如下
List<学生类型> 箱子 = new List<学生类型>();
你既然标注了这个箱子里面装的是学生,取出来的时候就直接拿就好了,如下
学生类型 学生 = 箱子[i];
把代码改改就成这样了:
using System;
using System.Collections.Generic;
namespace ConsoleApp
{
public class 学生类型
{
public string 名字 { get; set; }
}
class Program
{
//程序入口,我猜你应该知道这个吧
static void Main(string[] args)
{
//带学生标签的箱子
List<学生类型> 箱子 = new List<学生类型>(); // <-------------- 这里变了
for (int i = 0; i < 3; i++)
{
Console.WriteLine("你给我一个学生的名字吧:");
//看看用户输入啥名字
string 输入 = Console.ReadLine();
//如果输入了名字,新建一个学生,然后把把刚才输入的名字给放到这个学生的名字属性里
学生类型 学生 = new 学生类型 { 名字 = 输入 };
//把刚才那个学生装到箱子里备用
箱子.Add(学生);
}
for(int i = 0; i < 箱子.Count; i++)
{
//直接拿出来就用,不用弄(as)一下
学生类型 学生 = 箱子[i]; // <-------------- 这里变了
Console.WriteLine(学生.名字);
}
}
}
}
大家都喜欢整洁有序的东西,所以带标签的箱子比不带的要好。很多人要箱子的时候也希望箱子外面带了标签说明里面是什么。ArrayList 这种就是没地方写标签的箱子, List<空白> 这种就可以在空白处写东西的箱子,为了偷懒我们一般把 List<空白> 写成 List<T>。
ArrayList 和 List<T> 都是一种类型,但是因为 List<T> 他妈的居然带了一个标签,我们就管他叫 泛型,泛型是类型中的一种高级货,因为带了标签,传递给别人就很方便,大家都爱带有标签的东西。
当然除了可以装东西的箱子有标签,我们生活中很多东西都用标签:
就拿笔来说, Pen 上没有标签就一只 Pen ,鬼知道它什么颜色的,
Pen<T> 留了一个标签空位,写Red就成了 Pen<Red>,你就知道能写出红色的字了。
标签空位还不止一个,Pen<T1,T2> 上就贴了两个标签 Pen<Red,Thick> 马上就知道是红色粗笔头,找起来用起来都方便。
大家觉得在类型上贴标签上很方便呢,所以就决定在所有能留空位地方都留空位了,比如有些家伙就在方法上留了标签,这个方法就成了泛型方法
//把交给我的字符串转换成 T 类型
public T 转换成<T>(string 字符串)
这个方法留了一个标签空位(类型参数),你一看就知道了,你只要这个标签空位(类型参数)里填个什么东西,他就会想办法把转换成标签空位(类型参数)里的东西。
//字符串变成具体日期
DateTime 日期 = 转换成<DateTime>("今天");
//字符串大变活人
学生类型 学生 = 转换成<学生类型>("张三");
提供这个 转换成<T> 方法的人一看,这 <T> 留的太随意了,你已经开始叫他大变活人了。所以不让事态变的难以控制,他决不让你随便写标签,所以他跟你约法三章(泛型约束)只能出数字,或者日期啦,别的太复杂的不行啊。
//只能变成 struct 的东西啊
public T 转换成<T>(string 字符串) where T : struct
你看,现在你让他在大变活人,他就不干了,给你亮红线了,之前方法后面的那个
where T : struct
就是对 T 这个类型参数的约法三章啦,简称就是泛型约束咯,这些就是你需要知道的泛型最基础的内容了。
我已经尽我所能地简单易懂+中文编程了,因为我儿子上小学的时候C#泛型部分我是打算这么帮他入门的,相信你应该不会输给他吧。逃 [ε=ε=ε=┏(゜ロ゜;)┛]