泛型的理解
.NET FrameWork 2.0的语法 。
【应用】对于不同类型的参数,有着相同或类似的行为逻辑时,可以考虑使用泛型重用代码。
【原理】延迟声明,方法没有指定参数类型,而是在调用的时候指定。在编译的时候,类型参数编译为占位符,程序运行的时候,JIT及时编译替换为真实类型。
【扩展】泛型类、泛型委托、泛型方法、泛型接口。
普通类不能继承泛型类,必须指定泛型类型参数后才可以。
【泛型约束的五大类型,当然也可以多重约束,但是要注意约束直接的关系是否有嵌套】
public static T Get<T>() where T : new() //无参数构造函数约束
where T: class//引用类型约束
where T:struct //值类型约束
where T:Interface//接口约束
where T:People //基类约束(People在这里是一个class)
{
return default(T);//返回泛型类型的默认值,引用类型的默认值是null,值类型不是
}
【协变、逆变】
只能放在接口或者委托的泛型参数前面。
out 协变(covariant) 修饰返回值 c#中的IEnumerable泛型接口;
in 逆变(contravariant) 修饰传入参数 c#中的Action泛型委托;
public class Dog{} //狗的父类
public class Labrador:Dog{}//子类 拉布拉多
在继承关系上,父类出现的地方都可以用子类代替,因此下面的实例化都是可以的:
{
Dog dog = new Dog();
Dog dog = new Labrador();
}
{
List<Dog> dogs = new List<Dog>();// 语法是肯定没问题的
List<Dog> dogs = new List<Labrador>(); //语法是出错的
List<Dog> dogs = new List<Labrador>().Select(d=>(Dog)d).ToList(); //语法是通过的
}
上述的第二个方法块内的第二个实例化为什么会出错呢?讲道理拉布拉多是继承自狗的父类,一群拉布拉多也是一群狗,应该不会出错的。
虽然拉布拉多和狗是父子关系,但是List<Dog>和List<Labrador>不是父子关系,因此不能实例化。在c# 4.0的语法中出现协变和逆变的概念,允许我们这样操作,可以理解成是为了简化我们代码的操作
IEnumerable<out T> 是一个泛型接口,List继承这一泛型接口,out其实就是在告诉编译器,这里我们接受这样的一个自动转换
{//协变out,只能作为返回结果,不能作为传入
IEnumerable<Dog> dog = new List<Dog>();
IEnumerable<Dog> dog = new List<Labrador>();//这一次语法是通过的
}
{//逆变in,不能作为返回值,只能作为参数传入
IDogs<Labrador> dog = new List<Labrador>();
IDogs<Labrador> dog = new List<Dog>();//这一次语法是通过的
public interface IDogs<int T>{}
}
在实际的代码中我们可能并不需要自己去定义这样的协变和逆变,大部分是框架为我们定义好的,比如Func<string,int> string就是一个逆变,int就是一个逆变参数。
【泛型缓存】
在程序中一般用static做缓存,多以Dictionary来缓存数据。
然而泛型是程序在运行的时候,JIT及时编译替换为真实类型。
public class GenericCache<T> //泛型类
{
static GenericCache()
{
time = string.Format("{0}_{1}",typeof(T).FullName,DataTime.Now.ToString("yyyyMMddHHmmss.fff"));
}
private static string time = "";
public static string GetCatch()
{
return time;
}
}
//主程序调用
for(int i=0;i<5;i++)
{
GenericCache<int>.GetCatch();
GenericCache<string>.GetCatch();
GenericCache<DateTime>.GetCatch();
}
第一次循环进来,该类的构造函数会执行三次,静态的值也会被初始化三次;第二次循环进来,无需走构造函数,直接返回缓存值。
优缺点以及应用场景:
(1)速度快,第二次访问的时候不需要再堆栈中寻址,而是在CPU旁边直接访问;
(2)不同的类型只有一个值的时候可以应用
(3)缺点:缓存的清除麻烦

浙公网安备 33010602011771号