C#进阶之泛型(Generic)

1、泛型

泛型是framwork2.0推出的新语法,具有延迟声明的特点:把参数类型的声明推迟到调用的时候。泛型不是一个语法糖,是框架升级提供的功能。需要编辑器和JIT(just-in-time compilation、即时编译)的支持。

泛型并不存在性能问题,因为编译器支持 ,在即时编译的时候,编译器会生成一个泛型方法的副本,基本上和固定类型的方法性能无差别。

泛型的用处就是 用一个类、方法、接口、委托来满足不同的具体类型,然后做一样的事情。

泛型的约束有以下几种类型:

  1. 基类约束
  2. 接口约束
  3. 引用类型约束
  4. 值类型约束
  5. 无参数构造函数约束

约束必须是接口、非密封类(密封类无法被继承,不存在子类,所以约束没有意义)、类型参数;

约束可叠加,

泛型约束主要是用来保证代码安全。

  

2、协变逆变

 这里用代码来解释一下这两个概念

 1 using System;
 2 using System.Collections.Generic;
 3 
 4 namespace Util_YCH.Build.泛型
 5 {
 6     /// 
 7     /// 协变实例
 8     /// 
 9     /// 
10     public interface IListAnimals<out T> {
11         /// 
12         /// T只能作为返回值不能作为入参
13         /// 
14         /// 
15         T GetT();
16         /// 
17         /// 所以这里会编译报错
18         /// 
19         /// 
20         void setT(T t);
21     }
22     public class ListAnimals : IListAnimals
23     {
24         T t;
25         public T GetT()
26         {
27             throw new NotImplementedException();
28         }
29 
30         public void setT(T t)
31         { }
32     }
33     /// 
34     /// 逆变实例
35     /// 
36     /// 
37     public interface IListDogs<in T>
38     {
39         /// 
40         /// T只能作为入参不能作为返回值
41         /// 
42         /// 
43         void setT(T t);
44         /// 
45         /// T无法作为返回值,此处会编译报错
46         /// 
47         /// 
48         T GetT();
49 
50     }
51     public class ListDogs : IListDogs
52     {
53         public T GetT()
54         {
55             throw new NotImplementedException();
56         }
57 
58         public void setT(T t)
59         {
60             throw new NotImplementedException();
61         }
62     }
63     /// 
64     /// 动物类
65     /// 
66     public class Animal
67     {
68     }
69     /// 
70     /// 狗类
71     /// 
72     public class Dog : Animal
73     { 
74     }
75 
76     public class Test {
77         public Test(){
78 
79             Animal animal1 = new Animal();
80             Dog dog = new Dog();
81             Animal animal2 = new Dog();//狗是动物
82             List animals = new List();
83             //按照常规而言,Dog是Animal的子类,这样写应该是没有问题的,凡是编译器报错,
84             //原因是因为Dog是Animal的子类,但是List 与 List 之间不存在继承关系,
85             //于是为了消除这个BUG,就有了【协变】的概念
86             #region 协变
87             IListAnimals listAnimals = new ListAnimals();
88             #endregion
89             #region 逆变
90             IListDogs listAnimals2 = new ListDogs();
91             #endregion
92         }
93 
94     }
95 }

 

3、泛型缓存

由于CLR会针对不同的类型会生成一个副本,所以可以实现泛型的缓存,示例代码如下

 1 using System;
 2 
 3 namespace Util_YCH.Build.泛型
 4 {
 5     /// 
 6     /// 每个不同的类型T都会生成一个副本,
 7     /// 根据C#语言特性,静态字段和方法会在程序第一次运行的时候执行,缓存效率远远高于字典等缓存。
 8     /// 
 9     public class Cache
10     {
11         public Cache()
12         {
13             CacheStr = DateTime.Now.ToString();
14         }
15         private static string CacheStr = "";
16         public static string GetCacheStr() {
17             return CacheStr;
18         }
19     }
20 
21     public class Test {
22         public Test(){
23 
24             #region 泛型缓存
25             var cache1 = new Cache<int>();
26             var cache2 = new Cache<string>();
27             var cache3 = new Cache();
28             var cache4 = new Cache<double>();
29             var cache5 = new Cache<bool>();
30             #endregion
31 
32             var cache11 = Cache<int>.GetCacheStr();
33             var cache12 = Cache<int>.GetCacheStr();
34             Console.WriteLine(cache11 == cache12);
35             Console.ReadKey();
36         }
37 
38     }
39 }

字典缓存是哈希结构的,读取缓存的时候需要进行查找,会消耗一定的资源;而泛型缓存的副本存在于内存里面,查找起来速度极快,但是有局限性,就是和类型相关,具有一定的限制。

这里的应用场景我能想到的就是可以针对每个实体缓存CRUD的Sql语句。

 

你可能感兴趣的:(C#进阶之泛型(Generic))