泛型
什么是泛型
C# 语言和公共语言运行时 (CLR) 在 2.0 版本中添加了泛型。泛型将类型参数的概念引入 .NET Framework,这样就可以设计具有相同特征的类和方法:在客户端代码声明并初始化这些类和方法之前,这些类和方法会延迟指定一个或多个类型(使用占位符~3:数字代表类型参数个数)
泛型有什么用
使用泛型类型可以最大限度地重用代码、保护类型安全性以及提高性能。泛型最常见的用途是创建集合类 List< int>。
可以创建:泛型接口、泛型类、泛型方法、泛型事件和泛型委托。
泛型的好处
-
增加类型的安全性
-
提高代码的重用
泛型的使用
问题:
自己编写一个入栈和出栈的通用类(任何数据类型都可以使用)类似与实现一个List的基本功能
public class MyList<T>
{
//数组和集合
T[] stack;
int size;
int stacPoint;//当前位置指针
public MyList(int length)
{
this.size = length;
stack = new T[size];
stacPoint = -1;
}
/// <summary>
/// 入栈
/// </summary>
/// <param name="item"></param>
public void Add(T item)
{
if (stacPoint>=size)
{
Console.WriteLine("集合已满");
}
else
{
stacPoint++;
stack[stacPoint] = item;
}
}
/// <summary>
/// 出栈
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public T Pop()
{
//提供的索引是存在元素的
T data = stack[stacPoint];
stacPoint--;
return data;
}
}
泛型类的规范:
public class 类名<T> {类成员....}
-
T:仅代表一个占位符,用T或者其他字母都行,只要符合C#命名规范都行,但是一般情况用T
-
T:表示一个通用的数据类型,在使用的时候用实际类型代替
-
T:泛型类可以在定义中可以包含多个任意类型参数,参数之间使用逗号隔开
例如
public class 类名<T1,T2,T3,....>{...}
各种类型参数都可以用作成员变量的类型、属性、方法等成员的返回类型,以及方法的参数类型
总结:以上泛型类的使用,增加了类型安全,实例化时int类型的约束下是不能添加string类型。无需拆箱操作
泛型类型的问题
无法为泛型类型赋值初始化
因为泛型类型可以理解为泛指所有的数据类型,而所有的数据类型可分为:值类型和引用类型,而且不同的数据类型支持的默认值是不一样的。
注意:
-
不能随便假设泛型类型是某种类型,这种类型也许没有构造方法,也许是私有的
-
解决方案使用default关键字,如果defalut中指定的类型最终是引用类型则默认是null,如果是值类型那就给值类型对应的默认值,数值就是0.结构类型要根据具体的成员类型确定是0还是null
泛型约束有哪些
-
where T : struct 类型参数必须是值类型。
-
where T : class 类型参数必须是引用类型。 此约束还应用于任何类、接口、委托或数组类型。
-
where T : unmanaged 类型参数不能是引用类型,并且任何嵌套级别均不能包含任何引用类型成员。
-
where T : new() 类型参数必须具有公共无参数构造函数。
-
where T : <基类名> 类型参数必须是指定的基类或派生自指定的基类
-
where T : <接口名称> 类型参数必须是指定的接口或实现指定的接口
-
where T : U 为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。
dynamic动态类型:根据程序的执行去动态的获取当前类型是什么类型,类型永远不固定,最终类型取决于本次使用该数据时,其数据的类型
var推断类型:根据第一次的初始值推断出该类型,一旦类型被推断出,则该数据的类型就确定好了,之后不可更改
泛型方法
//泛型方法
static T Add<T>(T a,T b) where T:struct
{
dynamic a1 = a;
dynamic b1 = b;
return a1 + b1;
}