标签00标签01标签02
- 泛型类型
- 为什么需要泛型
- 泛型方法
- 声明类型参数
- typeof和未绑定泛型类型
- 泛型的默认值
- 泛型的约束
- 继承泛型类型
- 自引用泛型声明
- 类型参数的转换
- 协变
- 可变性不是自动的
- 数组
- 声明协变类型参数
- 逆变
- C#泛型和C++模板对比
:::tips
- C#有两种不同的机制来编写跨类型可复用的代码:继承和泛型。
- 继承的复用性来自于基类,泛型的复用性是通过”占位符“的”模板“类型来实现的。
和继承相比,泛型能够提高类型的安全性,并减少类型的转换和装箱。 :::
泛型类型
泛型类型中声明的类型参数(占位符类型)需要由泛型类型的消费者(即提供类型参数的一方)填充。=》使用的时候才能够确定泛型中参数对应的数据类型。
//泛型类Stack
//泛型对应的参数T,此时并不知道其具体的参数属于哪一种数据类型
public class Stack<T>
{
private int position;
private T[] data = new T[100];
public void Push(T obj) => data[position++] = obj;
public T Pop() => data[--position];
}
调用泛型类Stack
private static void Main(string[] args)
{
var stack = new Stack<int>(); //使用的时候,确定泛型参数的数据类型
//根据下标索引到数组并赋值
stack.Push(5); //position++=>1,data[0]=5
stack.Push(10); //position++=>2,data[1]=10
int x = stack.Pop(); //此时position=2,执行--position后=>1,即x=data[1]=10
int y = stack.Pop(); //此时position=1,执行--position后=>0,即y=data[0]=0
}
其实上面的泛型类Stack就类似于确定了T具体的数据类型
public class StackTemplate
{
private int position;
private int[] data = new int[100];
public void Push(int obj) => data[position++] = obj;
public int Pop() => data[--position];
}
:::success 温馨提示:
技术上,我们称Stack
是开放类型,称Stack 为封闭类型。 - 在运行时,所有的泛型实例都是封闭的,占位符已经被类型填充。这就意味着如下语句是非法的:
stack=new Stack<T>();
- 只有在类或者方法内部,T才可以定义为类型参数:
public class Stack
{
…
public Stack
{
Stack
}
…
}
:::
为什么需要泛型?
泛型是为了代码能够跨类型复用而设计的。