一、泛型
1.引入泛型
假如一个方法,让这个方法既能接收int也能接收string、DateTime等,该如何做到呢?
在.net framwork 1.0的时候,我们可以使用object类型来完成:
ShowObject(1);//int
ShowObject("2");//string
ShowObject(DateTime.Now);
public static void ShowObject(Object oParameter)
{
Console.WriteLine($"Type={oParameter.GetType().Name},Parameter={oParameter}");
}
Object:
1.Object类型是一切类型的父类
2.通过继承,子类拥有父类的一切属性和行为;任何父类出现的地方,都可以用子类来代替。
但是object是引用类型,传入一个值类型,会有装箱,拆箱
栈->堆 装箱
堆->栈 拆箱
且类型不安全
值类型作为方法中的局部变量时,在栈中分配,而作为类的成员变量时,在堆中分配;
引用类型变量在栈中分配,引用类型的实例在堆中分配
(引用类型变量好比一个指针,它所指向的内容即引用类型的实例)
为了解决这些问题,在.net framwork 2.0,推出了泛型。
2.如何声明和使用泛型
//泛型方法
T tNew = new T();
public static void show<T>(T per)
{
Console.WriteLine(per_T);
}
//泛型类
public class TClass<T>
{
public T _T;
}
TClass<int> tClass=new TClass<int>();
//泛型接口
public interface Gen<T>
{
T GetT(T t);
}
public class GenX : Gen<int>
{
public int GetT(int t)
{
throw new NotImplementedException();
}
}
public class GenY<T> : Gen<T>
{
public T GetT(T t)
{
throw new NotImplementedException();
}
}
//泛型委托
public delegate void SayH<T>(T t);
3.泛型的好处和原理:延迟声明
泛型:
1.解决用一个方法,满足不同参数类型,做相同的事;
2.类型可以自动推算;
3.类型必须保持一致;
4.编译时没有写死参数类型,调用才指定类型,称为延迟声明;
4.1延迟声明:把参数类型的声明推迟到调用(推迟一切可以推迟的,延迟思想)
例如:惰性加载网页 数据库等到所有过滤条件准备好在过滤 抢票网站,推迟任务
不是语法糖,需要编译器支持+JIT支持
编译器---------[]--------------->exe-------------->运行环境CLR里面的(JIT)[]-------------->机器码
-------- 泛型在[]产生占位符-----------------------------[]填入相关类型
//占位符验证
Console.WriteLine(typeof(List<>));
Console.WriteLine(typeof(Dictionary<,>));
System.Collections.Generic.List1[T] System.Collections.Generic.Dictionary
2[TKey,TValue]
4.泛型约束
T tNew = new T();
public static void show<T>(T per)
where T:TClass<int>
{
Console.WriteLine(per_T);
}
泛型约束(基类约束):where T:People 不能是Sealed密封类
1.可以使用基类的一切属性方法
2.强制保证T一定是Prople或其子类
where T: Gen//接口约束
where T:calss//引用类型约束
where T:struct//值类型约束
T tName=default(T);//会根据T的不同,赋予默认值
where T:new()//无参数构造约束
不能用基类,int 这种不行
约束可以叠加,更灵活
where T:Prope,IsSports,IWork,new()
5.协变、逆变
public class Bird
{
public int Id { get; set; }
}
public class Sparrow : Bird
{
public string Name { get; set; }
}
public static void Show()
{
{
Bird bird1 = new Bird();
Bird bird2 = new Sparrow();
}
{
List<Bird> birds = new List<Bird>();
//**********************************************************
//List<Bird> birds1 = new List<Sparrow>();
//List<Sparrow>不能付给List<Bird>,没有父子关系Brid与Sparrow有
//为了解决这个问题,提出了协变,逆变
//List<Bird> -----> List<Sparrow>() 协变
//List<Sparrow> -----> List<Bird>() 逆变
//**********************************************************
List<Bird> birds2 = new List<Sparrow>().Select(c => (Bird)c).ToList();
}
{
//协变
//用于接口或者委托
IEnumerable<Bird> birds = new List<Bird>();
IEnumerable<Bird> birds1 = new List<Sparrow>();
Func<Bird> func = new Func<Sparrow>(()=>null);
}
{
//自定义协变
ICustomerListOut<Bird> birds = new CustomerListOut<Bird>();
ICustomerListOut<Bird> birds1 = new CustomerListOut<Sparrow>();
}
{
//逆变
ICustomerListIn<Sparrow> birds = new CustomerListIn<Sparrow>();
ICustomerListIn<Sparrow> birds1 = new CustomerListIn<Bird>();
}
{
IMyList<Sparrow, Bird> myList = new MyList<Sparrow, Bird>();
IMyList<Sparrow, Bird> myList1 = new MyList<Sparrow, Sparrow>();//协变
IMyList<Sparrow, Bird> myList2 = new MyList<Bird, Bird>();//逆变
IMyList<Sparrow, Bird> myList3 = new MyList<Bird, Sparrow>();//逆变+协变
}
}
//协变的接口 只能是返回结果
public interface ICustomerListOut<out T>
{
T Get();
}
public class CustomerListOut<T> : ICustomerListOut<T>
{
public T Get()
{
return default(T);
}
}
//逆变 只能当参数,不能做返回值
public interface ICustomerListIn<in T>
{
void Show(T t);
}
public class CustomerListIn<T> : ICustomerListIn<T>
{
public void Show(T t)
{
;
}
}
//协变+逆变
public interface IMyList<in inT, out outT>
{
void Show(inT T);
outT Get();
outT Do(inT t);
}
public class MyList<T1, T2> : IMyList<T1, T2>
{
public T2 Do(T1 t)
{
Console.WriteLine(t.GetType().Name);
Console.WriteLine(typeof(T2).Name);
return default(T2);
}
public T2 Get()
{
Console.WriteLine(typeof(T2).Name);
return default(T2);
}
public void Show(T1 T)
{
Console.WriteLine(T.GetType().Name);
}
}
6.泛型缓存
//不同的T,都会生成一份不同的副本
//适合不同的类型,需要缓存一份数据的场景,效率高
public class GenericCache<T>
{
static GenericCache() //静态字段--静态构造
{
Console.WriteLine();
_TypeTime = string.Format("{0}_{1}", typeof(T).FullName, DateTime.Now.ToString());
}
private static string _TypeTime = "";
public static string GetCache()
{
return _TypeTime;
}
}
//都会重新构造,在调用一次就不回来
public static void Show2()
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine(GenericCache<int>.GetCache());//泛型的缓存
Thread.Sleep(10);
Console.WriteLine(GenericCache<long>.GetCache());
Thread.Sleep(10);
Console.WriteLine(GenericCache<string>.GetCache());
Thread.Sleep(10);
}
}
静态字典 与泛型相比,由于Key 要哈希,在查找,比泛型要慢
public class DictionaryCache //静态字典
{
private static Dictionary<Type, string> keyValuePairs = null;
static DictionaryCache()
{
keyValuePairs = new Dictionary<Type, string>();
}
public static string GetCache<T>()
{
Type type=typeof(Type);
if (!keyValuePairs.ContainsKey(type))
{
keyValuePairs[type] = string.Format("{0}_{1}", typeof(T).FullName, DateTime.Now.ToString());
}
return keyValuePairs[type];
}
}