解释泛型如何在 C# 中工作

泛型是在 C# 2.0 版中添加的,是该语言中最重要的概念之一。它们使您能够编写在编译时类型安全的可重用、高性能代码。使用泛型,您可以在代码中使用类型,而无需事先了解它。

泛型在 .NET 中的许多地方使用,包括集合、委托和异步代码。使用泛型,您无需事先知道集合的大小,并且可以将泛型用于任何元素类型,甚至是特定于代码的自定义数据类型。C# 提供对泛型类型(类、接口等)和泛型方法的支持。

在泛型中,您有类型参数和类型参数。这类似于具有参数的方法,您可以将参数传递给该方法。

通用类型

声明泛型类型的语法由类型名称后尖括号中的类型参数组成。例如, Locator<T> 是下面示例中的泛型类。

public class Locator<T>
{

}

要创建 Locator<T> 的实例,请使用 new 关键字,后跟类的名称。但是,您指定要作为参数传递的实际类型而不是 T。以下示例将字符串类型作为参数传递。

var stringLocator = new Locator<string>();

您可以在类方法上使用类型参数 (T),如下例所示。

public class Locator<T>{
   public IList<T> Items { get; set; }

      public T Locate(int index){
      return Items[index];
   }
}
var stringLocator = new Locator<string>();
string item = stringLocator.Locate(2);

泛型的另一个好处是编辑器提供的 IntelliSense。当您在 Visual Studio 或 VS Code 中键入 stringLocator.Locate(4) 并将鼠标悬停在方法名称上时;它将显示它返回一个字符串而不是 T。如果您尝试将结果分配给字符串以外的任何类型,编译器将引发错误。例如,

// 错误:无法将类型 'string' 隐式转换为 'int' [c-sharp]csharp(CS0029)
int item = stringLocator.Locate(2);

当从泛型基类型或泛型接口继承时,泛型类型可以使用类型参数作为类型参数。通用 LinkedList<T> 类型实现了通用 IEnumerable<T> 接口以及其他接口。

public class LinkedList<T> : IEnumerable<T>

通用方法

泛型方法只是一种声明类型参数的方法,您可以在方法内部使用它并作为参数和返回类型使用。在下面的示例中,Swap<T> 是一个泛型方法,它接受两个 T 类型的参数并返回 T 的一个实例。

public class Swapper{
   public T Swap<T>(T first, T second){
      T temp = first;
      first = second;
      second = temp;
      return temp;
   }
}

与泛型类型一样,当您调用泛型方法时,它将返回一个强类型变量。

var swapper = new Swapper();
int result = swapper.Swap<int>(5, 3);

可以有多个泛型参数。System.Collections.Generic 命名空间中的 Dictionary 类有两个类型参数,分别是键和值。

public class Dictionary<TKey, TValue>

最后,重要的是要知道什么可以是通用的。对于类型,除了枚举,一切都可以是泛型的。这包括 -

  • 班级

  • 结构

  • 接口

  • 代表

对于类型成员,只有方法和嵌套类型可以是泛型的。以下成员不能是通用的 -

  • 字段

  • 特性

  • 索引器

  • 构造函数

  • 活动

  • 终结者

示例

using System;
using System.Collections.Generic;
class Program{
   static void Main(){
      var stringLocator = new Locator<string>(){
         Items = new string[] { "JavaScript", "CSharp", "Golang" }
      };
      string item = stringLocator.Locate(1);
      Console.WriteLine(item); // 夏普
      var swapper = new Swapper();
      int a = 5, b = 3;
      int result = swapper.Swap<int>(ref a, ref b);
      Console.WriteLine($"a = {a}, b = {b}");
   }
}
public class Locator<T>{
   public IList<T> Items { get; set; }
   public T Locate(int index){
      return Items[index];
   }
}
public class Swapper{
   public T Swap<T>(ref T first, ref T second){
      T temp = first;
      first = second;
      second = temp;
      return temp;
   }
}
输出结果
CSharp
a = 3, b = 5