C#基础编程-泛型基础

1. 泛型的产生

 

泛型是在.NET 2.0的时候推出来的重要功能。在.NET 1.0时期,因为不支持泛型,所以开发人员在编写一些功能的时候只能以object为参数,然后在方法体内对参数进行转换,
采用这种编程模式容易出现以下问题:

1.效率低下:主要体现在传入的参数为值类型的对象,会涉及到拆箱/装箱的操作(引用类型的AS转换对性能的影响可以忽略不计);
2.容易出错: 采用object作为参数,然后在方法体中进行转换。因为没有其他约束,所以在编译时很难发现问题,只能在运行时才会出现问题;
3.代码可读性不高: 不能通过参数来判断传入的参数类型,只能在后面的转换代码中才能发现,可读性比较低。

而泛型的推出恰好解决了上面提到的问题

2. 创建泛型

泛型主要在类、接口、委托、方法中使用。泛型中的占位符可以有多个,只要不适用保留字就可以。
泛型类创建,语法如下:

class MyGenericClass<T>
{
    //其他代码
}

Framework中的List<T>, Queue<T>, Dictionary<Tkey, Tvalue>等都是常见的泛型类
泛型接口创建,语法如下:

interface MyGenericIntergace<T>
{
    //其他代码
}

Framework中的IList<T>, IDictionary<Tkey, Tvalue>等都是常见的泛型接口
泛型委托创建,语法如下:

delegate void MyGenericGelegate<T>();

Framework中的Action和Func等都是常见的泛型委托
泛型方法创建,语法如下:

public void SetName<T>(T name)
{
    //其他代码
}

3.使用泛型

泛型对象和普通对象在使用方面基本是一致的。例如:

MyGenericClass<int> t1 = new MyGenericClass<int>();     //创建泛型类的实例
t.SetName<string>("Demo");      //调用泛型方法

在.NET中编译器是足够智能的,能够根据给定的参数类型进行推算出占位符的类型。因此在这种情况下可以省略占位符。例如:

t.SetName<string>("Demo");      //占位符的类型为string
t.SetName("Demo");      //编译器能够根据参数类型为string自动推算出占位符为string,这个时候就可以省略占位符。效果和上面是一样的,但是书写更简单

4.泛型约束

如果没有泛型约束,那泛型的提出是没有任何意义的。因为没有指定任何约束的话,那么传入的参数T只能判断为是object类型,如果需要用到指定对象的方法,同样只能是进行类型转换,那这和不使用泛型是没有任何区别的。正是因为泛型约束的存在,才能够更好的利用泛型进行编程。
泛型主要提供了以下几种约束:

  • 结构约束
  • 类约束
  • 构造函数约束
  • 继承约束
  • 接口约束

1.结构约束:类型参数必须是值类型,如下所示:

class MyGenericClass<T> where T : struct
{
    //其他代码
}

此时T必须是int, datetime, struct等值类型的数据

2.类约束:类型参数必须是引用类型,如下所示

class MyGenericClass<T> where T : class
{
    //其他代码
}

此时T必须是引用类型的对象

3.构造函数约束:类型参数必须有无参数的构造函数,如下所示:

class MyGenericClass<T> where T : new()
{
    //其他代码
}

此时T必须有无参数的构造函数,可以是默认的,也可以是非默认的。泛型约束不能约束有参数的构造函数。

4.继承约束:类型参数必须继承自某个给定的基类

class MyGenericClass<T> where T : BaseClass
{
    //其他代码
}

此时T必须是BaseClass或者是其子类。继承约束在泛型约束中是比较常用的,因为指定了继承的基类,那么在方法体中就可以调用基类的成员对象,就可以根据多态进行自由的控制。继承约束最多只能指定一个基类(C#中的类最多只能继承一个基类,不支持多继承)

5.接口约束:类型参数必须实现指定的接口,如下所示:

class MyGenericClass<T> where IEnumerable<T>{
    //其他代码
}

此时T必须实现指定的接口。接口约束在泛型约束中也是比较常用的。并且因为C#支持实现多个接口,所以接口约束是可以指定多个的,为编写代码提供了很大的便利。
在反省约束中,可以同时指定多种约束,只要不矛盾即可,利用我们可以约束类型参数同时继承自某个基类,并且实现给定的接口。但是结构约束和类约束是不能同时指定的。很简单,因为不可能要求一个对象既是值类型,同时还是引用类型。

5.default默认值

在泛型中,因为类型参数是不固定的(值类型/引用类型),因此在对象创建以及返回值和普通方法有所区别。例如:在未指定类型参数为引用类型的话,方法的返回值不能设置为null,因为有可能为值类型。
为了解决这个问题,.NET Framework针对泛型的对象初始化方法,使用default关键字。
使用default创建的对象遵循以下规则:

  • 如果对象为值类型,则返回该值类型对象的默认值,例如int类型返回为0,DateTime类型返回的是当前的时间;
  • 如果对象为引用类型,则返回null(不会去调用无参数的构造函数)
posted @ 2018-07-19 17:27  hebutyll  阅读(159)  评论(0编辑  收藏  举报