C#学习笔记之——泛型(Generic)
泛型是将类型作为参数来传递。
泛型的优点:
1、使用泛型可以重用代码,保护类型的安全以及提高性能
为什么这样说,这里就有个例子
public void Swap(int x, int y)
{
int temp = x;
x = y;
y = temp;
}
public void Swap(char x, char y)
{
char temp = x;
x = y;
y = temp;
}
public void Swap(string x, string y)
{
string temp = x;
x = y;
y = temp;
}
可以看到相同的写法,只是参数不一样,这样写就特别浪费空间
2、降低强制转换或装箱操作的成本和风险
像上面这个代码确实可以用另一种方式代替,就是用object
public void Swap(object x, object y)
{
object temp = x;
x = y;
y = temp;
}
比如这样,但是用object会出现装拆箱操作,这将在托管堆上分配和回收大量的变量,若数据量大,则性能损失非常严重。在处理引用类型时,虽然没有装箱和折箱操作,但将用到数据类型的 强制转换操作,增加处理器的负担。
3、可以对泛型参数进行限定以访问特定数据类型的方法
可以限定数据类型
泛型类型参数的约束:关键字where
泛型类型参数常用的约束类型
1、where T:struct 要求是值类型参数
2、where T:class 要求是引用类型参数
3、where T:new() 要求这个泛型具有一个无参构造方法,如果有多个约束,这个要放在最后
4、where T:基类名 这个泛型是该父类或其子类
5、where T:接口名 泛型是实现了该接口的类型
6、where T:int(,string,char,bool等)
泛型类型参数注意点
1、泛型类型参数可以有多个
public void Swap<T, U> (T t, U u) { ... }
2、泛型类型参数可以是编译器识别的任何数据类型
3、泛型类型参数命名需要遵守命名规则
(1)使用描述性名称命名泛型类型,并且使用T作为前缀
(2)使用单个大写字母命名即可
泛型方法
格式: 访问修饰符 返回值类型 方法名<泛型类型参数>(参数列表){
方法体
}
调用的时候要加上具体参数类型,比如:
Swap<int, int>(a, a);
泛型方法重载
可以泛型类型参数进行重载
public void Swap() { }
public void Swap<T> {}
public void Swap<T, U> {}
泛型结构
修饰符 struct 结构体名<泛型类型参数>{
结构体成员
}
struct PieceOfData<T>
{
public PieceOfData(T value)
{
_data = value;
}
private T _data;
public T Data
{
get{ return _data; }
set{ _data = value; }
}
}
泛型类
修饰符 class 类名<泛型类型参数>{
类成员
}
public class Student<T>
{
类成员
}
泛型接口
修饰符 interface 接口名<泛型类型参数>{
}
public interface IMyInterface<T>
{
T ReturnIt(T inValue);
}
协变(convariance)、逆变(contravariance)和不变(invariance)
协变
class MyClass
{
static Dog MakeDog()
{
return new Dog();
}
static void Main(string[] args)
{
//Animal a1 = new Animal();
//Animal a2 = new Animal();
Facttory<Dog> dogMaker = MakeDog;
Facttory<Animal> animalMaker = dogMaker;//委托中泛型类型参数前不加out要报错
Console.WriteLine(animalMaker().NumberOfLegs.ToString());
}
}
//动物类
class Animal
{
public int NumberOfLegs = 4;
}
//狗类,继承自动物类
class Dog : Animal
{
}
delegate T Facttory<out T>();
逆变
class MyClass
{
delegate void Action1<in T>(T a);//in:逆变关键字
static void ActOnAnimal(Animal a)
{
Console.WriteLine(a.NumberOfLegs);
}
static void Main(string[] args)
{
Action1<Animal> act1 = ActOnAnimal;
Action1<Dog> dog1 = act1;
dog1(new Dog());
}
}
//动物类
class Animal
{
public int NumberOfLegs = 4;
}
//狗类,继承自动物类
class Dog : Animal
{
}
不变
不包括in和out关键字的委托和接口类型参数叫做不变。这些类型参数不能用于协变或逆变。