一. 泛型诞生的背景
在介绍背景之前,先来看一个案例,要求:分别输出实体model1、model2、model3的id和name值,这三个实体有相同的属性名字id和name。
1 public class myUtils 2 { 3 //要求:分别输出实体model1、model2、model3的id和name值,这三个实体有相同的属性名字id和name 4 5 //传统的解决方案(一):由于三个不同的实体,所以要声明三个不同的方法来输出 6 /* 7 缺点:该解决方案十分繁琐,明明相同的属性,不得不声明三个不同的方法,造成代码的大量冗余 8 */ 9 10 public static void showM1(model1 m1) 11 { 12 Console.WriteLine("id值为:" + m1.id + " name值为:" + m1.name); 13 } 14 15 public static void showM2(model2 m2) 16 { 17 Console.WriteLine("id值为:" + m2.id + " name值为:" + m2.name); 18 } 19 20 public static void showM3(model3 m3) 21 { 22 Console.WriteLine("id值为:" + m3.id + " name值为:" + m3.name); 23 } 24 25 26 //传统的解决方案(二):使用Object类型来解决该问题 27 //原理:object是所有类型的父类,所有用到父类的地方都可以用子类去代替,即:里氏替换原则 28 /* 29 缺点:需要记住可能会传进来哪几种类型;最大的问题是值类型和引用类型之间的互换(即拆箱和装箱)严重影响性能 30 */ 31 32 public static void showObj(object obj) 33 { 34 if (obj.GetType() == typeof(model1)) 35 { 36 model1 m = (model1)obj; 37 Console.WriteLine("id值为:" + m.id + " name值为:" + m.name); 38 } 39 else if (obj.GetType() == typeof(model2)) 40 { 41 model2 m = (model2)obj; 42 Console.WriteLine("id值为:" + m.id + " name值为:" + m.name); 43 } 44 else if (obj.GetType() == typeof(model3)) 45 { 46 model3 m = (model3)obj; 47 Console.WriteLine("id值为:" + m.id + " name值为:" + m.name); 48 } 49 50 } 51 52 //基于以上两种传统的解决方案都缺点明显,所以在 .Net 2.0的时候,推出了一个通用语言运行时(CRL)的新特性即:泛型。 53 /* 54 泛型为.NET框架引入了类型参数(type parameters)的概念。类型参数使得设计类和方法时,不必确定一个或多个具体参数,其的具体参数可延迟到客户代码中声明、实现。 55 这意味着使用泛型的类型参数T,可以多种形式调用,运行时类型转换避免了装箱操作的代价和风险。 56 57 */ 58 59 }
基于以上两种传统的解决方案都缺点明显,所以在 .Net 2.0的时候,推出了一个通用语言运行时(CLR)的新特性即:泛型。泛型为.NET框架引入了类型参数(type parameters)的概念,它属于System.Collections.Generic命名空间下。类型参数使得设计类和方法时,不必确定一个或多个具体参数,其的具体参数可延迟到客户代码中声明、实现。
这意味着使用泛型的类型参数T,可以多种形式调用,运行时类型转换避免了装箱操作的代价和风险。
二. 泛型的引入
为了解决上述问题,我们这里引入泛型的概念来解决代码冗余的问题和性能低下的问题。
这里统一说明一下:model1、model2、model3实体均继承与ModelFather实体,ModelFather实体中有两个属性,id和name,下同。
1 /// <summary> 2 /// 泛型方法的引入 3 /// </summary> 4 /// <typeparam name="T">T为泛型的一个标记,也可以用别的字母代替</typeparam> 5 /// <param name="t"></param> 6 public static void showModel<T>(T t) 7 { 8 Console.WriteLine(t); 9 } 10 11 /// <summary> 12 /// 泛型约束的引入,如果要输出实体中的值,需要配合“基类约束”方可以实现 13 /// </summary> 14 /// <typeparam name="T"></typeparam> 15 /// <param name="t"></param> 16 public static void showModelDetils<T>(T t) where T : ModelFather 17 { 18 Console.WriteLine("id值为:" + t.id + " name值为:" + t.name); 19 } 20 21 22 //总结: 23 /* 24 1. 以上两个方法均为泛型方法,T代表的类型在使用时才声明,俗称“延迟声明”。 25 2. 如果要使用类中的属性时,需要配合泛型的“基类约束”来实现 26 */
总结:
1. 以上两个方法均为泛型方法,T代表的类型在使用时才声明,俗称“延迟声明”。
2. 如果要使用类中的属性时,需要配合泛型的“基类约束”来实现。
说明:除了泛型方法外,还有泛型接口、泛型委托等,同样泛型约束除了“基类约束”外,还有其他约束。
三. 泛型的种类
泛型包括:泛型方法、泛型类、泛型接口、泛型委托四类。
这里主要介绍泛型方法,在后续会配合泛型的五种约束继续深入介绍。
1 /// <summary> 2 /// 泛型方法 3 /// </summary> 4 public class GenericsMethord 5 { 6 //这里介绍泛型方法,在之前02-泛型的引入中,使用的就是泛型方法,这里再重复一次 7 /* 8 详解:T为泛型的一个代表,换成别的字母同样可以 9 T和A代表的类型在使用时才声明,俗称“延迟声明” 10 */ 11 public static void ShowModel<T, A>(T model1, A model2) 12 where T : ModelFather 13 where A : model3 14 { 15 Console.WriteLine("id值为:" + model1.id + " name值为:" + model1.name); 16 Console.WriteLine("id值为:" + model2.id + " name值为:" + model2.name); 17 } 18 }