.NET 泛型

 

  • 泛型
     泛型将类型参数的概念引入 .NET Framework,类型参数使得设计以下类和方法成为可能:这些类和方法将一个或多个类型的指定推迟到客户端代码声明并实例化该类或方法的时候。例如,经过使用泛型类型参数 T,您能够编写其余客户端代码可以使用的单个类,而不致引入运行时强制转换或装箱操做的成本或风险。
     使用泛型类型能够最大限度地重用代码、保护类型的安全以及提升性能。泛型最多见的用途是建立集合类。能够建立本身的泛型接口、泛型类、泛型方法、泛型事件和泛型委托。能够对泛型类进行约束以访问特定数据类型的方法。关于泛型数据类型中使用的类型的信息可在运行时经过反射获取。
 
public class GenericList<T>
{
    void Add(T input) { }
}
class TestGenericList
{
    private class ExampleClass { }
    static void Main()
    {
        GenericList<int> list1 = new GenericList<int>();
        GenericList<string> list2 = new GenericList<string>();
        GenericList<ExampleClass> list3 = new GenericList<ExampleClass>();
    }
}
  • 泛型类型参数
    • 为泛型类、结构指定类型参数
    • 为泛型成员指定类型参数
    • 为泛型接口指定类型参数
  • 泛型默认值类型
    • 关键字:default
  • 非泛型集合
     System.Collections中大量的定义了非泛型集合类和接口
  • 经常使用类
    • ArrayList
    • Hashtable
    • Queue
    • SortedList
    • Stack
  • 经常使用接口
    • ICollection
    • ICloneable
    • IDictionary
    • IEnumerable
    • IEnumerator
    • IList
  • 性能问题
     使用非泛型集合时全部的数据都是被存放为object对象,因此在使用非泛型集合时存在装箱拆箱的过程,这是一个相似于数据转换的过程,若是存放的数据是值类型的还会涉及大量的内存堆栈转换操做,所以性能影响比较大。
  • 类型安全问题
     也是由于非泛型集合存放数据使用的是object对象,因此在拆箱的过程当中若是接收变量的类型与原类型不兼容则不会出现异常
 
  • 自定义泛型方法
     泛型方法是使用类型参数声明的方法,泛型方法是一个增强版的方法重载方式,该方法最大的优点在于,只要维护一个方法的版本,并且它能以类型安全的方式操做任意给定参数类型的项,更为重要的是栈数据保留在栈上,堆数据保留在堆上。
 
static void Swap<T>(ref T lhs, ref T rhs)
{
    T temp;
    temp = lhs;
    lhs = rhs;
    rhs = temp;
}
  • 自定义泛型类与结构
     泛型类封装不是特定于具体数据类型的操做。泛型类最经常使用于集合,如连接列表、哈希表、堆栈、队列、树等,其中,像从集合中添加和移除项这样的操做都以大致上相同的方式执行,与所存储数据的类型无关。
 
class BaseNode { }
class BaseNodeGeneric<T> { }
class NodeConcrete<T> : BaseNode { }
class NodeClosed<T> : BaseNodeGeneric<int> { }
class NodeOpen<T> : BaseNodeGeneric<T> { }
  • 泛型基类
     泛型类能够做为其余类的基类。
    • 派生规则
      • 若是非泛型类扩展泛型类,派生类必须指定一个类型参数。
      • 若是泛型基类定义了泛型虚方法和抽象方法,派生类必须使用指定类型参数重写泛型方法。
      • 若是派生类也是泛型,则它可以重用类型占位符,不过派生类必须遵守基类中的任何约束。
  • 类型参数的约束
     在定义泛型类时,能够对客户端代码可以在实例化类时用于类型参数的类型种类施加限制。若是客户端代码尝试使用某个约束所不容许的类型来实例化类,则会产生编译时错误。这些限制称为约束。约束是使用 where 上下文关键字指定的。
     若是要检查泛型列表中的某个项以肯定它是否有效,或者将它与其余某个项进行比较,则编译器必须在必定程度上保证它须要调用的运算符或方法将受到客户端代码可能指定的任何类型参数的支持。这种保证是经过对泛型类定义应用一个或多个约束得到的。例如,基类约束告诉编译器:仅此类型的对象或今后类型派生的对象才可用做类型参数。一旦编译器有了这个保证,它就可以容许在泛型类中调用该类型的方法。约束是使用上下文关键字 where 应用的。
 
class EmployeeList<T> where T : Employee, IEmployee, System.IComparable<T>, new() {}
  • 类型参数约束表
约束 说明

T:结构web

类型参数必须是值类型。能够指定除 Nullable 之外的任何值类型。有关更多信息,请参见使用可空类型(C# 编程指南)编程

T:类数组

类型参数必须是引用类型,包括任何类、接口、委托或数组类型。安全

T:new()函数

类型参数必须具备无参数的公共构造函数。当与其余约束一块儿使用时,new() 约束必须最后指定。性能

T:<基类名>spa

类型参数必须是指定的基类或派生自指定的基类。设计

T:<接口名称>orm

类型参数必须是指定的接口或实现指定的接口。能够指定多个接口约束。约束接口也能够是泛型的。对象

T:U

为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。这称为裸类型约束。

  • 未绑定的类型参数
     没有约束的类型参数(如公共类 SampleClass<T>{} 中的 T)称为未绑定的类型参数。未绑定的类型参数具备如下规则:
    • 不能使用 != 和 == 运算符,由于没法保证具体类型参数能支持这些运算符。
    • 能够在它们与 System.Object 之间来回转换,或将它们显式转换为任何接口类型。
    • 能够将它们与 null 进行比较。将未绑定的参数与 null 进行比较时,若是类型参数为值类型,则该比较将始终返回 false。
  • 裸类型约束
     用做约束的泛型类型参数称为裸类型约束。当具备本身的类型参数的成员函数须要将该参数约束为包含类型的类型参数时,裸类型约束颇有用。
 
class List<T>
{
    void Add<U>(List<U> items) where U : T {}
}
     
     在上面的示例中,T 在 Add 方法的上下文中是一个裸类型约束,而在 List 类的上下文中是一个未绑定的类型参数。
     裸类型约束还能够在泛型类定义中使用。注意,还必须已经和其余任何类型参数一块儿在尖括号中声明了裸类型约束:
 
public class SampleClass<T, U, V> where T : V { }
 
     泛型类的裸类型约束的做用很是有限,由于编译器除了假设某个裸类型约束派生自 System.Object 之外,不会作其余任何假设。在但愿强制两个类型参数之间的继承关系的状况下,可对泛型类使用裸类型约束。
相关文章
相关标签/搜索