C#2.0新增功能02 泛型

  • 2019 年 10 月 4 日
  • 笔记

  C# 语言和公共语言运行时 (CLR) 的 2.0 版本中添加了泛型。 泛型将类型参数的概念引入 .NET Framework,这样就可以设计具有以下特征的类和方法:在客户端代码声明并初始化这些类和方法之前,这些类和方法会延迟指定一个或多个类型。

泛型定义

 泛型是为所存储或使用的一个或多个类型具有占位符(类型形参)的类、结构、接口和方法。 泛型集合类可以将类型形参用作其存储的对象类型的占位符;类型形参呈现为其字段的类型和其方法的参数类型。 泛型方法可将其类型形参用作其返回值的类型或用作其形参之一的类型。

以下代码举例说明了一个简单的泛型类定义。

public class Generic<T>  {      public T Field;  }

创建泛型类的实例时,指定用于替代类型形参的实际类型。 在类型形参出现的每一处位置用选定的类型进行替代,这会建立一个被称为构造泛型类的新泛型类。 你将得到根据你选择的类型而定制的类型安全类,如以下代码所示。

public static void Main()  {      Generic<string> g = new Generic<string>();      g.Field = "A string";      //...      Console.WriteLine("Generic.Field           = "{0}"", g.Field);      Console.WriteLine("Generic.Field.GetType() = {0}", g.Field.GetType().FullName);  }

例如,通过使用泛型类型参数 T,可以编写其他客户端代码能够使用的单个类,而不会产生运行时转换或装箱操作的成本或风险,如下所示:

// 定义通用泛型类  public class GenericList<T>  {      public void Add(T input) { }  }    class TestGenericList  {      private class ExampleClass { }      static void Main()      {          // 定义 int 类型的集合          GenericList<int> list1 = new GenericList<int>();          list1.Add(1);            // 定义 string 类型的集合          GenericList<string> list2 = new GenericList<string>();          list2.Add("");            // 定义 ExampleClass 类类型的集合          GenericList<ExampleClass> list3 = new GenericList<ExampleClass>();          list3.Add(new ExampleClass());      }  }

  泛型类和泛型方法兼具可重用性、类型安全性和效率,这是非泛型类和非泛型方法无法实现的。 泛型通常与集合以及作用于集合的方法一起使用。 .NET Framework 2.0 版类库提供新的命名空间 System.Collections.Generic,其中包含几个新的基于泛型的集合类。 建议所有定目标到 .NET Framework 2.0 及更高版本的应用程序都使用新增的泛型集合类,而不是旧的非泛型集合类(如 ArrayList)。 有关详细信息,请参阅 .NET 中的泛型

当然,也可以创建自定义泛型类型和泛型方法,以提供自己的通用解决方案,设计类型安全的高效模式。 以下代码示例演示了出于演示目的的简单泛型链接列表类。 (大多数情况下,应使用 .NET Framework 类库提供的 List<T> 类,而不是自行创建类。)在通常使用具体类型来指示列表中所存储项的类型的情况下,可使用类型参数 T。 其使用方法如下:

  • AddHead 方法中作为方法参数的类型。
  • Node 嵌套类中作为 Data 属性的返回类型。
  • 在嵌套类中作为私有成员 data 的类型。

请注意,T 可用于 Node 嵌套类。 如果使用具体类型实例化 GenericList<T>(例如,作为 GenericList<int>),则出现的所有 T 都将替换为 int

// 泛型 T 类型的类  public class GenericList<T>  {      // 嵌套类也定义成泛型T类型      private class Node      {          // 泛型类型 T 作为构造函数参数          public Node(T t)          {              next = null;              data = t;          }            private Node next;          public Node Next          {              get { return next; }              set { next = value; }          }            // 定义一个私有 T(类型) 数据类型的变量          private T data;            // T 类型作为属性的返回类型          public T Data          {              get { return data; }              set { data = value; }          }      }        private Node head;        // 构造函数      public GenericList()      {          head = null;      }        // T 作为方法的参数类型      public void AddHead(T t)      {          Node n = new Node(t);          n.Next = head;          head = n;      }        public IEnumerator<T> GetEnumerator()      {          Node current = head;            while (current != null)          {              yield return current.Data;              current = current.Next;          }      }  }

以下代码示例演示了客户端代码如何使用泛型 GenericList<T> 类来创建整数列表。 只需更改类型参数,即可轻松修改以下代码,创建字符串或任何其他自定义类型的列表:

class TestGenericList  {      static void Main()      {          // 定义 int 类型的集合          GenericList<int> list = new GenericList<int>();            for (int x = 0; x < 10; x++)          {              list.AddHead(x);          }            foreach (int i in list)          {              System.Console.Write(i + " ");          }          System.Console.WriteLine("n 完成");      }  }

泛型主要有两个优点:

  • 编译时可以保证类型安全。
  • 不用做类型转换,获得一定的性能提升。

泛型概述

  • 使用泛型类型可以最大限度地重用代码、保护类型安全性以及提高性能。
  • 泛型最常见的用途是创建集合类。
  • .NET Framework 类库在 System.Collections.Generic 命名空间中包含几个新的泛型集合类。 应尽可能使用这些类来代替某些类,如 System.Collections 命名空间中的 ArrayList
  • 可以创建自己的泛型接口、泛型类、泛型方法、泛型事件和泛型委托。
  • 可以对泛型类进行约束以访问特定数据类型的方法。
  • 在泛型数据类型中所用类型的信息可在运行时通过使用反射来获取。