泛型的作用
跨类型可复用的代码:继承 和 泛型。
其中继承通过基类来代表代码的复用性,而泛型使用占位符(类型的占位符)
继承 → 基类
泛型 → 带有“(类型)占位符”的”模板“
泛型的类型(GENERIC TYPES)
泛型会声明类型参数 - 泛型的消费者需要提供类型参数(argument)来把占位符类型填充上。
public class Stack<T>{int position;T[] data = new T[100];public void Push(T obj) => data[position++] = obj;public T Pop() => data[--position];}var stack = new Stack<int>();stack.Push(5);stack.Push(10);int x = stack.Pop(); // x is 10int y = stack.Pop(); // x is 5// 相当于下面public class ###{int position;int[] data = new int[100];public void Push(int obj) =>data[position++] = obj;public int Pop() => data[--position];}
OPEN TYPE & CLOSED TYPE
Stack
Stack
在运行时,所有的泛型类型实例都是封闭的(占位符类型已经被填充了)
var stack = new Stack<T>(); //不合法的,因为占位符类型没有被填充public class Stack<T> //合法的{..public Stack<T> Clone(){Stack<T> clone = new Stack<T>();//..}}
为什么泛型会出现
public class ObjectStack{int position;object[] data = new object[100];public void Push(int obj) =>data[position++] = obj;public object Pop() => data[--position];}
为了可以写出适应不同类型的代码,如果没有
需要装箱和向下转换,这种转换在编译时无法进行检查
satck.Push("s";) //不同的类型,但是没有报错int i = (int)stack.Pop(); //向下装换 运行时错误,因为他不是int类型
泛型方法
泛型方法在方法签名内也可以声明类型参数
static void Swap<T>(ref T a, ref T b){T temp = a;a = b;b = temp;}static void Main(string[] args){int x = 5;int y = 10;Swap(ref x, ref y);Console.WriteLine($"{x},{y}"); // Input 10,5}
如果发生歧义,不知道类型的类型的话可以swap
(ref x, ref y)这样写 - 在方形类型里面的方法,除非也引入了类型参数(type parameters),否则是不会归为泛型方法的。
只有类型和方法可以引入类型参数,属性、索引器、实践、字段、构造函数、操作符等等都不可以声明类型参数。但是他们可以使用他们所在的泛型类型的类型参数。public class Stack<T>{int position;T[] data = new T[100];public void Push(T obj) => data[position++] = obj;//这引用的T,是在泛型类型那声明的,而不是方法引入的,就是没有是用<>来引入其它的类型参数(占位符),所以说这个Pop()方法它不是泛型方法,只不过是泛型类型里面的一个普通方法public T Pop() => data[--position];}
public T this[int index] => data[index];public Stack<T>() {} //构造函数引入一个类型参数是不合理的
声明类型参数
在声明class、struct、internal、delegate的时候可以引用类型参数(Type parameters)。
其它的例如属性,就不可以引入类型参数,但是可以使用类型参数。
public struct Nullable<T>{public T Value {get;} //可以使用}
泛型类型/泛型方法可以有多个类型参数:
class Dictionary<TKey,Tvalue>{..}
Dictionary<int,string> myDic = new Dictionary<int,string>();
var myDic = new Dictionary<int,string>();
泛型类型/泛型方法的名称可以被重载,条件是参数类型的个数不同:
class A{}
class A<T>{}
class A<T1,T2>{}
按约定,泛型类型/泛型方法,如果只有一个类型参数,那么就叫T。
当使用多个类型参数的时候,每个类型参数都使用T作为前缀,随后跟着具有描述性的一个名字。
TYPEOF 与未绑定的泛型类型
开放的泛型类型在编译后就编程了封闭的泛型类型。
但是如果作为Type对象,那么未绑定的泛型类型在运行时还是可以存在的。
(只能通过typeof操作符来实现)
class A<T>{}
class A<T1,T2>{}
Type a1 = Typeof(A<>) //联合类型,注意没有类型参数
Type a2 = Typeof(A<,>) //使用逗号表示多个类型参数
开放的泛型类型,通常与反射的API一起来使用的
Type a3 = typeof(A<int,int>);
class B<T>
{
void x()
{
Type t =typeof(T);
}
}
泛型的默认值
使用default关键字来获取泛型类型参数的默认值。
static void Zap<T>(T[] array)
{
for(int i =0; i< array.Length; i++)
array[i] = default(T);
}
