泛型(generic)是C#语言2.0和通用语言运行时(CLR)的一个新特性。泛型为.NET框架引入了类型参数(type parameters)的概念。类型参数使得设计类和方法时,不必确定一个或多个具体参数,其的具体参数可延迟到客户代码中声明、实现。这意味着使用泛型的类型参数T,写一个类MyList<T>,客户代码可以这样调用:MyList<int>, MyList<string>或 MyList<MyClass>。这避免了运行时类型转换或装箱操作的代价和风险。
在没有出现泛型的时候,我们输出int类型的值时:
输出string类型的值时:
输出DateTime类型的值时:
等。。。输出一个写一个方法,这是最原始的方法,性能也是最高的,但我们搞开发的追求精益求精!
后来我们广大的劳动人民想到了一个办法也就是在.net framework 1.1时代劳动人民智慧的结晶,提供一个ShowObject(object oParameter)方法
1 引入泛型:延迟声明
这个方法也会存在一个问题,就是传递值类型的时候,如:int类型,在传递时,把值类型转化为引用类型时涉及到装箱,在使用时,把这个引用类型再次转化为值类型时就涉及到拆箱,有追求性能方面的就会关注这个问题!其中还涉及到里面的属性值无法访问到,还有一个类型安全问题!因此微软提出了一种全新的解决方案--泛型(Generic)
2 如何声明和使用泛型:
3 泛型的好处和原理
泛型就是为了解决我们相同内容或者相同操作但是我们传递的类型不同的时候,对于不同类型的参数,我们有相同的行为的时候,我们希望能够重用起来!
4 泛型类、泛型方法、泛型接口、泛型委托
泛型就使用在四个地方,泛型方法,泛型类,泛型接口,泛型委托
泛型写起来简单,下面接下来泛型中有点麻烦的事,泛型类的继承,接口实现方面的问题
5 泛型约束
一共就这5种约束,约束可以叠加使用!基类约束,接口约束,引用类型约束,值类型约束,无参数构造函数约束!
6 协变 逆变
C# 4.0中,.net framework3.5中引用的!
class="code_img_closed" src="/Upload/Images/2017092602/0015B68B3C38AA5B.gif" alt="">1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace MyGeneric.Extend 8 { 9 /// <summary> 10 /// 只能放在接口或者委托的泛型参数前面 11 /// out 协变covariant 修饰返回值 12 /// in 逆变contravariant 修饰传入参数 13 /// </summary> 14 public class CCTest 15 { 16 public static void Show() 17 { 18 //IEnumerable<int> 19 //Action<int> act = null; 20 { 21 Bird bird1 = new Bird(); 22 Bird bird2 = new Sparrow();//元素Bird和Sparrow具有继承关系,所以可以指向子类,没毛病! 23 Sparrow sparrow1 = new Sparrow(); 24 //Sparrow sparrow2 = new Bird(); 25 } 26 27 { 28 //List<int> intList = new List<int>(); 29 List<Bird> birdList1 = new List<Bird>(); 30 31 //List<Bird> birdList2 = new List<Sparrow>();//List<Bird>和List<Sparrow>不是父子关系,没有继承关系 32 //一群麻雀一定是一群鸟理解上面是这样可以理解,但程序不认识这个逻辑,程序只认识继承关系而List<Bird>和List<Sparrow>时没有继承关系的所以通过不了 33 34 List<Bird> birdList3 = new List<Sparrow>().Select(c => (Bird)c).ToList(); 35 } 36 37 {//协变 38 IEnumerable<Bird> birdList1 = new List<Bird>(); 39 40 IEnumerable<Bird> birdList2 = new List<Sparrow>();//协变 为了程序能识别此种情况,为了方便,减少了类型转换,避免编译器转换僵硬的问题,这是因为微软当初推出泛型时,忘记了咱门还有此种要求,泛型父类可以指向泛型子类 41 //一群麻雀一定是一群鸟 42 43 Func<Bird> func = new Func<Sparrow>(() => null); 44 45 ICustomerListOut<Bird> customerList1 = new CustomerListOut<Bird>(); 46 ICustomerListOut<Bird> customerList2 = new CustomerListOut<Sparrow>(); 47 } 48 49 50 51 {//逆变 52 ICustomerListIn<Sparrow> customerList2 = new CustomerListIn<Sparrow>(); 53 ICustomerListIn<Sparrow> customerList1 = new CustomerListIn<Bird>(); 54 55 ICustomerListIn<Bird> birdList1 = new CustomerListIn<Bird>(); 56 birdList1.Show(new Sparrow()); 57 birdList1.Show(new Bird()); 58 59 Action<Sparrow> act = new Action<Bird>((Bird i) => { }); 60 } 61 62 63 { 64 IMyList<Sparrow, Bird> myList1 = new MyList<Sparrow, Bird>(); 65 IMyList<Sparrow, Bird> myList2 = new MyList<Sparrow, Sparrow>();//协变 66 IMyList<Sparrow, Bird> myList3 = new MyList<Bird, Bird>();//逆变 67 IMyList<Sparrow, Bird> myList4 = new MyList<Bird, Sparrow>();//协变+逆变 68 69 //Func<string,long> 70 } 71 } 72 } 73 74 /// <summary> 75 /// 鸟 76 /// </summary> 77 public class Bird 78 { 79 public int Id { get; set; } 80 } 81 /// <summary> 82 /// 麻雀 83 /// </summary> 84 public class Sparrow : Bird 85 { 86 public string Name { get; set; } 87 } 88 89 90 91 92 93 /// <summary> 94 /// 逆变 95 /// </summary> 96 /// <typeparam name="T"></typeparam> 97 public interface ICustomerListIn<in T> 98 { 99 //T Get();//不能作为返回值,只能作为参数传递 100 101 void Show(T t); 102 } 103 104 public class CustomerListIn<T> : ICustomerListIn<T> 105 { 106 //public T Get() 107 //{ 108 // return default(T); 109 //} 110 111 public void Show(T t) 112 { 113 } 114 } 115 116 /// <summary> 117 /// out 协变 只能是返回结果 118 /// </summary> 119 /// <typeparam name="T"></typeparam> 120 public interface ICustomerListOut<out T> 121 { 122 T Get(); 123 124 //void Show(T t);//T不能作为传入参数 125 } 126 127 /// <summary> 128 /// 类没有协变逆变 129 /// </summary> 130 /// <typeparam name="T"></typeparam> 131 public class CustomerListOut<T> : ICustomerListOut<T> 132 { 133 public T Get() 134 { 135 return default(T); 136 } 137 138 //public void Show(T t) 139 //{ 140 141 //} 142 } 143 144 145 146 147 148 public interface IMyList<in inT, out outT> 149 { 150 void Show(inT t); 151 outT Get(); 152 outT Do(inT t); 153 154 ////out 只能是返回值 in只能是参数 155 //void Show1(outT t); 156 //inT Get1(); 157 158 } 159 160 public class MyList<T1, T2> : IMyList<T1, T2> 161 { 162 163 public void Show(T1 t) 164 { 165 Console.WriteLine(t.GetType().Name); 166 } 167 168 public T2 Get() 169 { 170 Console.WriteLine(typeof(T2).Name); 171 return default(T2); 172 } 173 174 public T2 Do(T1 t) 175 { 176 Console.WriteLine(t.GetType().Name); 177 Console.WriteLine(typeof(T2).Name); 178 return default(T2); 179 } 180 } 181 182 }logs_code_collapse">View Code
Func<string,long> 这种方式就用到了协变,逆变!
7 泛型缓存
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace MyGeneric.Extend { public class GenericCacheTest { public static void Show() { //走的是静态字典中,在去字典中去读! 都是全局的 for (int i = 0; i < 5; i++) { Console.WriteLine(DictionaryCache.GetCache<int>()); Thread.Sleep(10); Console.WriteLine(DictionaryCache.GetCache<long>()); Thread.Sleep(10); Console.WriteLine(DictionaryCache.GetCache<DateTime>()); Thread.Sleep(10); Console.WriteLine(DictionaryCache.GetCache<string>()); Thread.Sleep(10); Console.WriteLine(DictionaryCache.GetCache<GenericCacheTest>()); Thread.Sleep(10); } //走的是泛型缓存 都是全局的 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<DateTime>.GetCache()); Thread.Sleep(10); Console.WriteLine(GenericCache<string>.GetCache()); Thread.Sleep(10); Console.WriteLine(GenericCache<GenericCacheTest>.GetCache()); Thread.Sleep(10); } } } /// <summary> /// 经常做缓存的一种方式 /// 字典缓存:静态属性常驻内存 /// </summary> public class DictionaryCache { private static Dictionary<string, string> _TypeTimeDictionary = null; static DictionaryCache() { Console.WriteLine("This is DictionaryCache 静态构造函数"); _TypeTimeDictionary = new Dictionary<string, string>(); } public static string GetCache<T>() { Type type = typeof(T); if (!_TypeTimeDictionary.ContainsKey(type.Name)) { _TypeTimeDictionary[type.Name] = string.Format("{0}_{1}", typeof(T).FullName, DateTime.Now.ToString("yyyyMMddHHmmss.fff")); } return _TypeTimeDictionary[type.Name]; } } /// <summary> /// 每个不同的T,都会生成一份不同的副本,解决特定场景,保存固定数据,如:程序中的配置文件,配置项! /// 适合不同类型,需要缓存一份数据的场景,效率高,速度快!就在cup旁边用时直接拿(好处) /// 不能清除 /// </summary> /// <typeparam name="T"></typeparam> public class GenericCache<T> { static GenericCache() { Console.WriteLine("This is GenericCache 静态构造函数"); _TypeTime = string.Format("{0}_{1}", typeof(T).FullName, DateTime.Now.ToString("yyyyMMddHHmmss.fff")); } private static string _TypeTime = ""; public static string GetCache() { return _TypeTime; } } }View Code