一、泛型引入
需求:传入一个类型(整型/日期/字符串或其他),打印出它的类型和内容。
初级版
1 public class CommonMethod
2 {
3 /// <summary>
4 /// 打印int值
5 /// </summary>
6 /// <param name="iParameter"></param>
7 public static void ShowInt(int iParameter)
8 {
9 Console.WriteLine("This is {0},parameter={1},type={2}",
10 typeof(CommonMethod).Name, iParameter.GetType().Name, iParameter);
11 }
12
13 /// <summary>
14 /// 打印string值
15 /// </summary>
16 /// <param name="sParameter"></param>
17 public static void ShowString(string sParameter)
18 {
19 Console.WriteLine("This is {0},parameter={1},type={2}",
20 typeof(CommonMethod).Name, sParameter.GetType().Name, sParameter);
21 }
22
23 /// <summary>
24 /// 打印DateTime值
25 /// </summary>
26 /// <param name="dParameter"></param>
27 public static void ShowDateTime(DateTime dParameter)
28 {
29 Console.WriteLine("This is {0},parameter={1},type={2}",
30 typeof(CommonMethod).Name, dParameter.GetType().Name, dParameter);
31 }
32 }
View Code
typeof和gettype的区别
调用
1 static void Main(string[] args)
2 {
3 DateTime dt = DateTime.Now;
4 int i = 5;
5 string test = "test";
6 object o = new object();
7 CommonMethod.ShowDateTime(dt);
8 CommonMethod.ShowInt(i);
9 CommonMethod.ShowString(test);
10 }
View Code
2.升级版
1 /// <summary>
2 /// 打印object值
3 /// 1.object是一切类型的基础
4 /// 2.通过集成,子类拥有父类的一切属性和行为
5 /// </summary>
6 /// <param name="o"></param>
7 public static void ShowObject(object oParameter)
8 {
9 Console.WriteLine("This is {0},parameter={1},type={2}",
10 typeof(CommonMethod).Name, oParameter.GetType().Name, oParameter);
11 }
View Code
调用
1 DateTime dt = DateTime.Now;
2 int i = 5;
3 string test = "test";
4 object o = new object();
5 CommonMethod.ShowObject(dt);
6 CommonMethod.ShowObject(i);
7 CommonMethod.ShowObject(test);
8 CommonMethod.ShowObject(o);
View Code
缺点:如果传递的是值类型,会装箱拆箱
二、泛型来喽
定义泛型
1 public class GenericMethod
2 {
3 /// <summary>
4 /// 方法名字后面带上尖括号 类型参数
5 /// T可以换成其他任何未定义的名称,但是不要用关键字、类名等等
6 /// 来自 .net framework2.0 CLR升级的
7 /// 解决相同内容/操作,对于不同参数的问题
8 ///
9 /// 延迟声明,声明方法的时候没有指定参数类型,而是等到调用的时候指定
10 /// 延迟思想:推迟一切可以推迟的
11 ///
12 /// 编译的时候 类型参数编译为占位符 `(1旁边英文输入状态)
13 /// 程序运行的时候,jit即时编译替换为真实类型
14 ///
15 ///
16 /// </summary>
17 /// <param name="o"></param>
18 public static void Show<T>(T tParameter)
19 {
20 Console.WriteLine("This is {0},parameter={1},type={2}",
21 typeof(CommonMethod).Name, tParameter.GetType().Name, tParameter);
22 }
23 }
View Code
调用
1 GenericMethod.Show<DateTime>(dt);
2 GenericMethod.Show(dt);//不指定类型参数,编译器自动推算(编译器的语法糖)
3 GenericMethod.Show<int>(i);
4 GenericMethod.Show<string>(test);
5 GenericMethod.Show<object>(o);
View Code
三、消耗时间对比
1 using System;
2 using System.Diagnostics;
3
4 namespace MyGeneric
5 {
6 public class Monitor
7 {
8 public static void Show()
9 {
10 Console.WriteLine("******************Monitor****************");
11 int iValue = 123456;
12 long commonSecond = 0;
13 long objectSecond = 0;
14 long genericSecond = 0;
15
16 {
17 Stopwatch watch = new Stopwatch();
18 watch.Start();
19 for (int i = 0; i < 100000000; i++)
20 {
21 ShowInt(iValue);
22 }
23 watch.Stop();
24 commonSecond = watch.ElapsedMilliseconds;
25 }
26
27 {
28 Stopwatch watch = new Stopwatch();
29 watch.Start();
30 for (int i=0;i<100000000;i++)
31 {
32 ShowObject(iValue);
33 }
34 watch.Stop();
35 objectSecond = watch.ElapsedMilliseconds;
36 }
37 {
38 Stopwatch watch = new Stopwatch();
39 watch.Start();
40 for (int i = 0; i < 100000000; i++)
41 {
42 Show(iValue);
43 }
44 watch.Stop();
45 genericSecond = watch.ElapsedMilliseconds;
46 }
47 Console.WriteLine("commonSecond={0},objectSecond={1},genericSecond={2}",
48 commonSecond, objectSecond, genericSecond);
49 Console.Read();
50 }
51
52
53 public static void ShowInt(int iParameter)
54 {
55 //do nothing
56 }
57
58
59 public static void ShowObject(object oParameter)
60 {
61 //do nothing
62 }
63
64 public static void Show<T>(T tParameter)
65 {
66 //do nothing
67 }
68 }
69 }
View Code
调试启动的时间如下,可以看出泛型执行的时间是最短的。
如果更换顺序,将执行泛型的方法放到第一位的话,会出现泛型时间和普通时间一样,甚至还会比它耗费时间长的情况。
ctrl+F5启动时间对比如下(这一块不懂,为什么普通方法要比泛型的时间快呢)
四、泛型类
1 using System;
2
3 namespace MyGeneric
4 {
5 //泛型类
6 public class GenericClass<W,Jasmine,Apple>//参数类型可以随便指定,意思就是相当于在这个类中定义了一个w的类型
7 {
8 public void Show(W w) { }
9 public Jasmine Get()
10 {
11 return default(Jasmine);
12 }
13 }
14 /// <summary>
15 /// 泛型接口
16 /// </summary>
17 /// <typeparam name="T"></typeparam>
18 public interface IStudy<T>
19 {
20 T Study(T t);
21 }
22 public delegate Everything GetHandler<Everything>();//泛型委托
23
24 /// <summary>
25 /// 普通类
26 /// </summary>
27 public class Child
28 //: GenericClass<string,int,string> //指定类型参数后即可继承
29 //:GenericClass<W, Jasmine, Apple> 这种写法是错误的,普通类不能直接继承泛型类
30 //:IStudy<T> 普通类不能直接实现泛型接口
31 : IStudy<string>
32 {
33 public string Study(string t)
34 {
35 throw new NotImplementedException();
36 }
37 }
38
39
40 public class GenericChild<W,Jasmine, Apple>
41 //: GenericClass<W,Jasmine,Apple> //泛型类可以直接继承泛型类
42 //public class GenericChild<W, Jasmine>//等于声明了两个局部类型 W和Jasmin
43 //: GenericClass<W, Jasmine, string>
44 :IStudy<W> //泛型类不能直接实现泛型接口
45 {
46 public W Study(W t)
47 {
48 throw new NotImplementedException();
49 }
50 }
51
52 }
View Code
五、泛型约束
1.所需模型
1 using System;
2
3 namespace MyGeneric
4 {
5 public class Model
6 {
7 public class People
8 {
9 public int Id { get; set; }
10 public string Name { get; set; }
11 public void Hi()
12 {
13 }
14 }
15
16 public interface ISports
17 {
18 void PingPang();
19 }
20
21 public interface IWork
22 {
23 void Work();
24 }
25
26 public class Chinese : People,ISports,IWork
27 {
28 public void Tradition()
29 {
30 Console.WriteLine("谦虚");
31 }
32 public void SayHi()
33 {
34 }
35
36 public void PingPang()
37 {
38 throw new NotImplementedException();
39 }
40
41 public void Work()
42 {
43 throw new NotImplementedException();
44 }
45 }
46
47 public class Sichuan : Chinese
48 {
49 public string Panda { get; set; }
50 public void Huoguo()
51 {
52 Console.WriteLine("吃火锅啦");
53 }
54 }
55 }
56
57 }
View Code
2.泛型约束(基类约束)
1 using System;
2 using static MyGeneric.Model;
3
4 namespace MyGeneric
5 {
6 public class Constraint
7 {
8 /// <summary>
9 /// 有约束才有自由,有权利就得有义务
10 ///
11 /// 1.基类约束,就可以访问基类的方法和属性(基类/子类)
12 /// </summary>
13 /// <typeparam name="T"></typeparam>
14 /// <param name="tParameter"></param>
15 public static void Show<T>(T tParameter) where T : People //基类约束
16 {
17 Console.WriteLine("This is {0},parameter={2},type={1}",
18 typeof(CommonMethod).Name, tParameter.GetType().Name, tParameter);
19
20 Console.WriteLine(tParameter.Id);
21 Console.WriteLine(tParameter.Name);
22 tParameter.Hi();
23 }
24 }
25 }
View Code
调用
1 People people = new People()
2 {
3 Id = 1,
4 Name = "张三"
5 };
6 Chinese chinese = new Chinese()
7 {
8 Id = 2,
9 Name = "李四"
10 };
11 Sichuan sichuan = new Sichuan()
12 {
13 Id = 3,
14 Name = "小红"
15 };
16
17 Constraint.Show(people);
18 Constraint.Show(chinese);
19 Constraint.Show(sichuan);
View Code
3.泛型约束(接口约束)
1 public static void ShowSports<T>(T tParameter) where T : ISports //基类约束
2 {
3 Console.WriteLine("This is {0},parameter={2},type={1}",
4 typeof(CommonMethod).Name, tParameter.GetType().Name, tParameter);
5
6 tParameter.PingPang();
7 }
View Code
调用和上面的相同,实现了该接口的类,可直接当做参数传入。
4.其他泛型约束写法
1 public static T Get<T>()
2 //where T:class //引用类型约束
3 //where T:struct//值类型约束
4 where T:new() //无参数构造函数约束
5 {
6 T t = new T();
7 return default(T);
8 }
View Code
六、协变
1.相关模型(Sparrow是Bird的子类)
1 public class Bird
2 {
3 }
4
5 public class Sparrow : Bird
6 {
7 }
View Code
2.
1 Bird bird1 = new Bird();
2 //左边父类,右边子类
3 Bird bird2 = new Sparrow();
4 Sparrow sparrow1 = new Sparrow();
5 List<Bird> birdList1 = new List<Bird>();
6 //List<Bird> bird3 = new List<Sparrow>(); //不是父子关系,没有继承关系
7
8 List<Bird> birdlist2 = new List<Sparrow>().Select(s => (Bird)s).ToList();
View Code
3.查看IEnumerable定义,可以看到有一个关键字out
4.下面可实现左边是父类,右边是子类
1 //协变
2 IEnumerable<Bird> birdList4 = new List<Bird>();
3 IEnumerable<Bird> birdList5 = new List<Sparrow>();//协变
View Code
5.具体应用
1 /// <summary>
2 /// out协变 只能是返回值
3 /// 协变逆变只存在于接口或者委托
4 /// </summary>
5 /// <typeparam name="T"></typeparam>
6 public interface ICustomerListOut<out T>
7 {
8 T Get();
9 //void Show(T t); // 此处错误,T不能作为传入参数
10 }
11
12 /// <summary>
13 /// 类没有协变逆变
14 /// </summary>
15 /// <typeparam name="T"></typeparam>
16 public class CustomerListOut<T> : ICustomerListOut<T>
17 {
18 public T Get()
19 {
20 return default(T);
21 }
22 }
View Code
调用
1 ICustomerListOut<Bird> customerList = new CustomerListOut<Bird>();
2 ICustomerListOut<Bird> customerList1 = new CustomerListOut<Sparrow>(); //协变
View Code
七、逆变
1.定义
1 public interface ICustomerListIn<in T>
2 {
3 //T Get();
4
5 void Show(T t);
6 }
7
8 /// <summary>
9 /// 逆变 只能作为参数传入
10 /// </summary>
11 /// <typeparam name="T"></typeparam>
12 public class CustomerListIn<T> : ICustomerListIn<T>
13 {
14 //T Get(); //不能作为返回值
15
16 public void Show(T t)
17 {
18 }
19 }
View Code
2.调用
1 //逆变
2 ICustomerListIn<Sparrow> customerList2 = new CustomerListIn<Sparrow>();
3 ICustomerListIn<Sparrow> customerList3 = new CustomerListIn<Bird>(); //左边是子类的时候,右边可以是父类
4
5 ICustomerListIn<Bird> birdList6 = new CustomerListIn<Bird>();
6 birdList6.Show(new Sparrow());
7 birdList6.Show(new Bird());
View Code
八、协变逆变混合应用
1.定义
1 public interface IMyList<in inT, out outT>
2 {
3 void Show(inT t);
4 outT Get();
5 outT Do(inT t); //out只能是返回值 in只能是参数
6 }
7
8 public class MyList<T1, T2> : IMyList<T1, T2>
9 {
10
11 public void Show(T1 t)
12 {
13 Console.WriteLine(t.GetType().Name);
14 }
15 public T2 Get()
16 {
17 Console.WriteLine(typeof(T2).Name);
18 return default(T2);
19 }
20 public T2 Do(T1 t)
21 {
22 Console.WriteLine(t.GetType().Name);
23 Console.WriteLine(typeof(T2).Name);
24 return default(T2);
25 }
26 }
View Code
2.调用
1 IMyList<Sparrow, Bird> myList1 = new MyList<Sparrow, Bird>();
2 IMyList<Sparrow, Bird> myList2 = new MyList<Sparrow, Sparrow>(); //协变
3 IMyList<Sparrow, Bird> myList3 = new MyList<Bird, Bird>(); //逆变
4 IMyList<Sparrow, Bird> myList4 = new MyList<Bird, Sparrow>(); //逆变
View Code
九、泛型缓存
不太懂,有时间再好好研究下(捂脸......)