C# 泛型的使用

01—泛型概述

       泛型是用于处理算法、数据结构的一种编程方法。泛型的目标是采用广泛适用和可交互性的形式来表示算法和数据结构,以使它们能够直接用于软件构造。泛型类、结构、接口、委托和方法可以根据它们存储和操作的数据的类型来进行参数化。泛型能在编译时提供强大的类型检查,减少数据类型之间的显式转换、装箱操作和运行时的类型检查。泛型类和泛型方法同时具备可重用性、类型安全和效率高等特性,这是非泛型类和非泛型方法无法具备的。泛型通常用在集合和在集合上运行的方法中。.
       泛型主要是提高了代码的重用性,例如,可以将泛型看成是一个可以回收的包装箱 A。如果在包装箱 A 上贴上苹果标签,就可以在包装箱A 里装上苹果进行发送;如果在包装箱 A 上贴上地瓜标签就可以在包装箱 A 里装上地瓜进行发送。
 
02—泛型的使用
       在下面内容中将会详细介绍泛型的类型参数 T,以及如何创建泛型接口和泛型方法,并且通过实例演示泛型接口和泛型方法在程序中的应用。
1. 类型参数T
泛型的类型参数 T 可以看作是一个占位符,它不是一种类型,它仅代表了某种可能的类型。类型参数T可以在使用时用任何类型来代替。类型参数T的命名准则如下。
      C# 泛型的使用  使用描述性名称命名泛型类型参数,除非单个字母名称完全可以让人了解它表示的含义,而描述性名称不会有更多的意义。
     【例1】 使用代表一定意义的单词作为类型参数T的名称。
      代码如下:
   public interface ISessionChannel<Session>
   public delegate TOutput Converter<input, Output>
 
     C# 泛型的使用  将T作为描述性类型参数名的前缀。
    【例2】 使用T作为类型参数名的前缀。
      代码如下:
  public interface ISessionChannel<TSession>  {          TSession Session{ get;}  }
2.  泛型接口
泛型接口的声明形式如下: 
interface 【接口名】<T>
{
          【接口体】
}

       声明泛型接口时,与声明一般接口的唯一区别是增加了一个<T>。一般来说,声明泛型接口与声明非泛型接口遵循相同的规则。泛型类型声明所实现的接口必须对所有可能的构造类型都保持唯一,否则就无法确定该为某些构造类型调用哪个方法。

       说明 
              在实例化泛型时也可以使用约束对类型参数的类型种类施加限制,约束是使用 where 上下文关键字指定的,下面列出了 6种类型的约束。
      ① T:结构——类型参数必须是值类型。可以指定除 Nullable 以外的任何值类型。
      ② T:类——类型参数必须是引用类型。这一点也适用于任何类、接口、委托或数组类型。
      ③ T:new()——类型参数必须具有无参数的公共构造函数,当与其他约束一起使用时,new()约束必须最后指定。
      ④ T:<基类名>——类型参数必须是指定的基类或派生自指定的基类。
      ⑤ T:<接口名称>——类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束,约束接口也可以是泛型的。
      ⑥ T:U——为T提供的类型参数必须是为 U提供的参数或派生自为 U提供的参数,这称为裸类型约束。
     【例3】 创建一个控制台应用程序,首先创建一个 Factory 类,在该类中建立一个CreateInstance方法。然后再创建一个泛型接口,在这个泛型接口中调用 Createlnstance 方法。根据类型参数 T,获取其类型。
      代码如下:
  //创建一个泛型接口  public interface IGenericInterface<T>  {            T CreateInstance();    //接口中调用 CreateInstance 方法   }  //实现上面泛型接口的泛型类  //派生约束 where T: TI(T 要继承自 TI)  //构造函数约束 where T:new()(T 可以实例化)  public class Factory<T,TI>;IGenericInterface<TI> where T: TI,new()  {       public TI CreateInstance()    //创建一个公共方法 CreateInstance  {                 return new T();      }}class Program{        static void Main(string[] args)        {        //实例化接口                 IGenericInterface<System.ComponentModel.IListSource> factory =        new Factory<System.Data.DataTable,System.ComponentModel.IListSource>();           //输出指定泛型的类型                 Console.WriteLine(factory.CreateInstance().GetType().ToString());          Console.ReadLine();        }}

程序的运行结果如图1 所示。

C# 泛型的使用

图1  泛型接口应用

3.  泛型方法

泛型方法的声明形式如下:

【修饰符】 Void 【方法名】<类型参数T>
{
    【方法体】
}

泛型方法是在声明中包括了类型参数T的方法。泛型方法可以在类、结构或接口声明中声明,这些类、结构或接口本身可以是泛型或非泛型。如果在泛型类型声明中声明泛型方法,则方法体可以同时引用该方法的类型参数T和包含该方法的声明的类型参数 T。

说明

       泛型方法可以使用多类型参数进行重载。

     【例4】 创建一个控制台应用程序,通过定义一个泛型方法来查找数组中某个数字的位置。

      代码如下:

  public class Finder     //建立一个公共类 Finder  {  public static int Find<T>(T[] items,T item)     //创建泛型方法   {      for(int i= 0;i < items.Length;i++)          //调用 for 循环       {           if(items[i].Equals(item))            //调用 Equals 方法比较两个数            {                 return i;                     //返回相等数在数组中的位置           }      }      return -1;                              //如果不存在指定的数,则返回-1    }}class Program{    static void Main(string[] args)    {         int i= Finder.Find<int>(new int[](1,2,3,4,5,6,8,9),6);    //调用泛型方法,并定义数组指定数字          Console.WriteLine("6 在数组中的位置:"+i.ToString());     //输出中数字在数组中的位置          Console.ReadLine();     }}

程序的运行结果是“6 在数组中的位置为5”。