泛型编程简述

一、什么是泛型

泛型是通过参数化类型来实现在同一份代码上操作多种数据类型。利用“参数化类型”将类型抽象化,从而实现灵活的复用。

泛型的优点:1.可以做到最大的代码重用、保护类型的安全以及提高了程序运行的性能;

      2.可以创建集合类;

      3.可以创建自己的泛型接口、泛型方法、泛型类、泛型事件和泛型委托。

      4.可以对泛型类进行约束,以访问特定数据类型的方法。

      5.关于泛型数据类型中使用的类型的信息,可在运行时通过反射获取。

例子:

 1 class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             int obj1 = 2;
 6             var task = new Task<int>(obj1);
 7             Console.WriteLine(task.obj);
 8 
 9             string obj2 = "这是个泛型";
10             var task2 = new Task<string>(obj2);
11             Console.WriteLine(task2.obj);
12             Console.ReadKey();
13             
14         }
15     }
16 
17     class Task<T>
18     {
19         public T obj;
20         public Task(T t)
21         {
22             this.obj = t;
23         }
24     }

上述是通过定义泛型类,并通过在创建泛型类时,通过构造函数来改变字段的值;根据不同类型,得到不同类型的结果;

二、泛型约束

下表列出五种类型的约束:

 

约束

说明

T:struct 类型参数必须是值类型。可以指定除 Nullable 以外的任何值类型。
T:class 类型参数必须是引用类型,包括任何类、接口、委托或数组类型。
T:new() 类型参数必须具有无参数的公共构造函数。当与其他约束一起使用时,new() 约束必须最后指定。
T:<基类名> 类型参数必须是指定的基类或派生自指定的基类。
T:<接口名称> 类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的。
T:U 为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。这称为裸类型约束.

 

 

 

 

 

 

派生约束

1.常见的

public class MyClass5<T> where T :IComparable { }

2.约束放在类的实际派生之后

public class B { }

public class MyClass6<T> : B where T : IComparable { }

3.可以继承一个基类和多个接口,且基类在接口前面

public class B { }

public class MyClass7<T> where T : B, IComparable, ICloneable { }

构造函数约束

1.常见的

public class MyClass8<T> where T :  new() { }

2.可以将构造函数约束和派生约束组合起来,前提是构造函数约束出现在约束列表的最后

public class MyClass8<T> where T : IComparable, new() { }

等等一些约束,因本人理解未深入在此也无法一一简介;

三、泛型的协变与逆变

“协变”是指能够使用与原始指定的派生类型相比,派生程度更大的类型。 

“逆变”则是指能够使用派生程度更小的类型。

直白的理解: 

“协变”->”和谐的变”->”很自然的变化”->string->object :协变。 

“逆变”->”逆常的变”->”不正常的变化”->object->string 逆变。 

通过以下一段代码,来简单看下:

 1 /// <summary>
 2     /// 3     /// </summary>
 4     public class Bird
 5     {
 6         public int Id { get; set; }
 7     }
 8     /// <summary>
 9     /// 麻雀
10     /// </summary>
11     public class Sparrow : Bird
12     {
13         public string Name { get; set; }
14     }

 我们分别取实例化这个类,发现程序是能编译通过的。

Bird bird1 = new Bird();
Bird bird2 = new Sparrow();
Sparrow sparrow1 = new Sparrow();

  //Sparrow sparrow2 = new Bird();//这个是编译不通过的,违反了继承性。

但是我们放在集合中,去实例化,是无法通过的

List<Bird> birdList1 = new List<Bird>();

//List<Bird> birdList2 = new List<Sparrow>();//不是父子关系,没有继承关系
//一群麻雀一定是一群鸟

那么我们如何去实现在泛型中的继承性呢??这就引入了协变和逆变得概念,为了保证类型的安全,C#编译器对使用了 out 和 in 关键字的泛型参数添加了一些限制:

  • 支持协变(out)的类型参数只能用在输出位置:函数返回值、属性的get访问器以及委托参数的某些位置
  • 支持逆变(in)的类型参数只能用在输入位置:方法参数或委托参数的某些位置中出现。

引用文献:

https://www.cnblogs.com/wangbaicheng1477865665/p/OutIn.html 王柏成

https://www.cnblogs.com/kudsu/p/7727615.html 发配三千里

 

posted @ 2019-03-15 20:18  宇易  阅读(741)  评论(0)    收藏  举报