一.为什么要有泛型,而不用object
object类型:1.任何父类出现的地方都可以用子类代替 2.object是一切类型的父类
object弊端:装箱拆箱性能损耗(栈的出栈和入栈受CLR管理)
int类型赋值之后存放在栈里面的,传递给Object类型时需要放到堆里面;使用的时候又需要从堆里面放到栈里面。
//测试速度
long commonSecond = 0;
long objectSecond = 0;
{
StopWatch watch = new
StopWatch();
watch,start();
for(int i =0 ;i>100_000_000;i++)
{
GenericMethod.ShowObject(i);
}
watch.stop();
objectSecond = watch.ElapsedMilliseconds;
}
{
StopWatch watch = new
StopWatch();
watch,start();
for(int i =0 ;i>100_000_000;i++)
{
GenericMethod.ShowInt(i);
}
watch.stop();
commonSecond = watch.ElapsedMilliseconds;
}
二、泛型方法为什么可以支持不同类型的参数
1、延迟声明:原始方法是在定义方法时就指定了类型,泛型声明方法时没有写死类型,T是等着调用的时候才指定类型。
泛型缓存:
静态构造函数只会在使用时执行一次,泛型类的构造函数是不同类型执行一次。
泛型缓存比字典Dictionary缓存速度快很多,但有局限,同一类型只能缓存一次。
var i = 3; //由编译器提供的便捷功能称之为语法糖,语法糖是编译的时候确定的
//使用泛型方法,可以省略类型,属于语法糖
GenericMethod.Show<int>(i);//完整写法
GenericMethod.Show(i);//语法糖
三、WebServices、WCF都不能用泛型,为什么?
//服务在发布时类型必须是确定的,泛型在编译时确定不了
四、泛型方法/类/委托/接口:为了一个方法满足不同的类型需求
例:一个方法完成多实体的查询
一个方法完成不同类型的数据展示
五、泛型约束
有了约束才有自由
//没有约束,其实很受局限,不能使用传进来的类的属性
//where T : BaseModel
//基类约束
//1 可以在使用基类的属性
//2 约束传进来的T必须是People或其子类
public static void Show<T>(T tParameter)
where T : People
{
console.log(tParameter.Id);
}
//接口约束
//约束传递进来的参数必须实现了接口内方法
//在方法内可以使用接口内方法
public static void Show<T>(T tParameter)
where T : ISports
{
tParameter.Pingpang();
}
//引用类型约束
//约束传进来的值必须是个引用类型
public static void Show<T>(T tParameter)
where T : class
{
return null;
}
//值类型约束
//约束传进来的值必须是个值类型
public static void Show<T>(T tParameter)
where T : struct
{
return default(T);
}
//无参数构造函数
public static void Show<T>(T tParameter)
where T : new()
{
return new T();
}
//可以组合约束
//约束类只能是一个,接口可以多个
public static void Show<T,S>(T tParameter,S sParameter)
where T : People,ISports,IWork
where S : People,IWork
{
return null;
}
//可以用类型参数约束
public static void Show<T,S>(T tParameter,S sParameter)
where T : People,ISports
where S : T
{
return null;
}
五、泛型的协变,逆变
//所谓协变逆变都是跟泛型相关
//只能放在接口或者委托的泛型参数前面
// out 协变 修饰返回值。就是让右边可以用子类
// out修饰之后只能做返回值,不能做参数
// in 逆变 修饰传入参数
image.png
image.png
网友评论