.NET 中的泛型Generics in .NET

借助泛型,可以根据要处理的精确数据类型定制方法、类、结构或接口。Generics let you tailor a method, class, structure, or interface to the precise data type it acts upon. 例如,不使用允许键和值为任意类型的 Hashtable 类,而使用 Dictionary<TKey,TValue> 泛型类并指定允许的密钥类型和允许的值的类型。For example, instead of using the Hashtable class, which allows keys and values to be of any type, you can use the Dictionary<TKey,TValue> generic class and specify the type allowed for the key and the type allowed for the value. 泛型的优点包括:代码的可重用性增加,类型安全性提高。Among the benefits of generics are increased code reusability and type safety.

本主题概述了 .NET 中的泛型,并总结了泛型类型或方法。This topic provides an overview of generics in .NET and a summary of generic types or methods. 它包含下列部分:It contains the following sections:

定义和使用泛型Defining and Using Generics

泛型是为所存储或使用的一个或多个类型具有占位符(类型形参)的类、结构、接口和方法。Generics are classes, structures, interfaces, and methods that have placeholders (type parameters) for one or more of the types that they store or use. 泛型集合类可以将类型形参用作其存储的对象类型的占位符;类型形参呈现为其字段的类型和其方法的参数类型。A generic collection class might use a type parameter as a placeholder for the type of objects that it stores; the type parameters appear as the types of its fields and the parameter types of its methods. 泛型方法可将其类型形参用作其返回值的类型或用作其形参之一的类型。A generic method might use its type parameter as the type of its return value or as the type of one of its formal parameters. 以下代码举例说明了一个简单的泛型类定义。The following code illustrates a simple generic class definition.

generic<typename T>
public ref class Generics
{
public:
    T Field;
};
public class Generic<T>
{
    public T Field;
}
Public Class Generic(Of T)
    Public Field As T

End Class

创建泛型类的实例时,指定用于替代类型形参的实际类型。When you create an instance of a generic class, you specify the actual types to substitute for the type parameters. 在类型形参出现的每一处位置用选定的类型进行替代,这会建立一个被称为构造泛型类的新泛型类。This establishes a new generic class, referred to as a constructed generic class, with your chosen types substituted everywhere that the type parameters appear. 你将得到根据你选择的类型而定制的类型安全类,如以下代码所示。The result is a type-safe class that is tailored to your choice of types, as the following code illustrates.

static void Main()
{
    Generics<String^>^ g = gcnew Generics<String^>();
    g->Field = "A string";
    //...
    Console::WriteLine("Generics.Field           = \"{0}\"", g->Field);
    Console::WriteLine("Generics.Field.GetType() = {0}", g->Field->GetType()->FullName);
}
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);
}
Public Shared Sub Main()
    Dim g As New Generic(Of String)
    g.Field = "A string"
    '...
    Console.WriteLine("Generic.Field           = ""{0}""", g.Field)
    Console.WriteLine("Generic.Field.GetType() = {0}", g.Field.GetType().FullName)
End Sub

泛型术语Generics terminology

介绍 .NET 中的泛型需要用到以下术语:The following terms are used to discuss generics in .NET:

  • 泛型类型定义 是用作模板的类、结构或接口声明,带有可包含或使用的类型的占位符。A generic type definition is a class, structure, or interface declaration that functions as a template, with placeholders for the types that it can contain or use. 例如, System.Collections.Generic.Dictionary<TKey,TValue> 类可以包含两种类型:密钥和值。For example, the System.Collections.Generic.Dictionary<TKey,TValue> class can contain two types: keys and values. 由于泛型类型定义只是一个模板,所以你无法创建作为泛型类型定义的类、结构或接口的实例。Because a generic type definition is only a template, you cannot create instances of a class, structure, or interface that is a generic type definition.

  • 泛型类型参数(或类型参数)是泛型类型或方法定义中的占位符。Generic type parameters, or type parameters, are the placeholders in a generic type or method definition. System.Collections.Generic.Dictionary<TKey,TValue> 泛型类型具有两个类型形参 TKeyTValue,它们分别代表密钥和值的类型。The System.Collections.Generic.Dictionary<TKey,TValue> generic type has two type parameters, TKey and TValue, that represent the types of its keys and values.

  • 构造泛型类型(或 构造类型)是为泛型类型定义的泛型类型形参指定类型的结果。A constructed generic type, or constructed type, is the result of specifying types for the generic type parameters of a generic type definition.

  • 泛型类型实参 是被泛型类型形参所替代的任何类型。A generic type argument is any type that is substituted for a generic type parameter.

  • 一般术语 泛型类型 包括构造类型和泛型类型定义。The general term generic type includes both constructed types and generic type definitions.

  • 借助泛型类型参数的协变逆变,可以使用类型自变量的派生程度比目标构造类型更高(协变)或更低(逆变)的构造泛型类型。Covariance and contravariance of generic type parameters enable you to use constructed generic types whose type arguments are more derived (covariance) or less derived (contravariance) than a target constructed type. 协变和逆变统称为“变体” 。Covariance and contravariance are collectively referred to as variance. 有关详细信息,请参阅协变和逆变For more information, see Covariance and Contravariance.

  • 约束是对泛型类型参数的限制。Constraints are limits placed on generic type parameters. 例如,你可能会将一个类型形参限制为实现 System.Collections.Generic.IComparer<T> 泛型接口的类型,以确保可对该类型的实例进行排序。For example, you might limit a type parameter to types that implement the System.Collections.Generic.IComparer<T> generic interface, to ensure that instances of the type can be ordered. 此外,你还可以将类型形参限制为具有特定基类、具有无参数构造函数或作为引用类型或值类型的类型。You can also constrain type parameters to types that have a particular base class, that have a parameterless constructor, or that are reference types or value types. 泛型类型的用户不能替换不满足约束条件的类型实参。Users of the generic type cannot substitute type arguments that do not satisfy the constraints.

  • 泛型方法定义 是具有两个形参列表的方法:泛型类型形参列表和形参列表。A generic method definition is a method with two parameter lists: a list of generic type parameters and a list of formal parameters. 类型形参可作为返回类型或形参类型出现,如以下代码所示。Type parameters can appear as the return type or as the types of the formal parameters, as the following code shows.

generic<typename T>
T Generic(T arg)
{
    T temp = arg;
    //...
    return temp;
}
T Generic<T>(T arg)
{
    T temp = arg;
    //...
    return temp;
}
Function Generic(Of T)(ByVal arg As T) As T
    Dim temp As T = arg
    '...
    Return temp
End Function

泛型方法可出现在泛型或非泛型类型中。Generic methods can appear on generic or nongeneric types. 值得注意的是,方法不会仅因为它属于泛型类型或甚至因为它有类型为封闭类型泛型参数的形参而成为泛型方法。It is important to note that a method is not generic just because it belongs to a generic type, or even because it has formal parameters whose types are the generic parameters of the enclosing type. 只有当方法有属于自己的类型形参列表时才是泛型方法。A method is generic only if it has its own list of type parameters. 在以下代码中,只有方法 G 是泛型方法。In the following code, only method G is generic.

ref class A
{
    generic<typename T>
    T G(T arg)
    {
        T temp = arg;
        //...
        return temp;
    }
};
generic<typename T>
ref class Generic
{
    T M(T arg)
    {
        T temp = arg;
        //...
        return temp;
    }
};
class A
{
    T G<T>(T arg)
    {
        T temp = arg;
        //...
        return temp;
    }
}
class Generic<T>
{
    T M(T arg)
    {
        T temp = arg;
        //...
        return temp;
    }
}
Class A
    Function G(Of T)(ByVal arg As T) As T
        Dim temp As T = arg
        '...
        Return temp
    End Function
End Class
Class Generic(Of T)
    Function M(ByVal arg As T) As T
        Dim temp As T = arg
        '...
        Return temp
    End Function
End Class

返回页首Back to top

泛型的利与弊Advantages and disadvantages of generics

使用泛型集合和委托有很多好处:There are many advantages to using generic collections and delegates:

  • 类型安全。Type safety. 泛型将类型安全的负担从你那里转移到编译器。Generics shift the burden of type safety from you to the compiler. 没有必要编写代码来测试正确的数据类型,因为它会在编译时强制执行。There is no need to write code to test for the correct data type because it is enforced at compile time. 降低了强制类型转换的必要性和运行时错误的可能性。The need for type casting and the possibility of run-time errors are reduced.

  • 代码更少且可以更轻松地重用代码。Less code and code is more easily reused. 无需从基类型继承,无需重写成员。There is no need to inherit from a base type and override members. 例如,可立即使用 LinkedList<T>For example, the LinkedList<T> is ready for immediate use. 例如,你可以使用下列变量声明来创建字符串的链接列表:For example, you can create a linked list of strings with the following variable declaration:

    LinkedList<String^>^ llist = gcnew LinkedList<String^>();
    
    LinkedList<string> llist = new LinkedList<string>();
    
    Dim llist As New LinkedList(Of String)()
    
  • 性能更好。Better performance. 泛型集合类型通常能更好地存储和操作值类型,因为无需对值类型进行装箱。Generic collection types generally perform better for storing and manipulating value types because there is no need to box the value types.

  • 泛型委托可以在无需创建多个委托类的情况下进行类型安全的回调。Generic delegates enable type-safe callbacks without the need to create multiple delegate classes. 例如, Predicate<T> 泛型委托允许你创建一种为特定类型实现你自己的搜索标准的方法并将你的方法与 Array 类型比如 FindFindLastFindAll方法一起使用。For example, the Predicate<T> generic delegate allows you to create a method that implements your own search criteria for a particular type and to use your method with methods of the Array type such as Find, FindLast, and FindAll.

  • 泛型简化动态生成的代码。Generics streamline dynamically generated code. 使用具有动态生成的代码的泛型时,无需生成类型。When you use generics with dynamically generated code you do not need to generate the type. 这会增加方案数量,在这些方案中你可以使用轻量动态方法而非生成整个程序集。This increases the number of scenarios in which you can use lightweight dynamic methods instead of generating entire assemblies. 有关详细信息,请参阅如何:定义和执行动态方法 DynamicMethodFor more information, see How to: Define and Execute Dynamic Methods and DynamicMethod.

以下是泛型的一些局限:The following are some limitations of generics:

  • 泛型类型可从多数基类中派生,如 MarshalByRefObject (约束可用于要求泛型类型形参派生自诸如 MarshalByRefObject的基类)。Generic types can be derived from most base classes, such as MarshalByRefObject (and constraints can be used to require that generic type parameters derive from base classes like MarshalByRefObject). 不过,.NET Framework 不支持上下文绑定泛型类型。However, the .NET Framework does not support context-bound generic types. 泛型类型可派生自 ContextBoundObject,但尝试创建该类型实例会导致 TypeLoadExceptionA generic type can be derived from ContextBoundObject, but trying to create an instance of that type causes a TypeLoadException.

  • 枚举不能具有泛型类型形参。Enumerations cannot have generic type parameters. 枚举偶尔可为泛型(例如,因为它嵌套在被定义使用 Visual Basic、C# 或 C++ 的泛型类型中)。An enumeration can be generic only incidentally (for example, because it is nested in a generic type that is defined using Visual Basic, C#, or C++). 有关详细信息,请参阅 Common Type System中的“枚举”。For more information, see "Enumerations" in Common Type System.

  • 轻量动态方法不能是泛型。Lightweight dynamic methods cannot be generic.

  • 在 Visual Basic、C# 和 C++ 中,包含在泛型类型中的嵌套类型不能被实例化,除非已将类型分配给所有封闭类型的类型形参。In Visual Basic, C#, and C++, a nested type that is enclosed in a generic type cannot be instantiated unless types have been assigned to the type parameters of all enclosing types. 另一种说法是:在反射中,定义使用这些语言的嵌套类型包括其所有封闭类型的类型形参。Another way of saying this is that in reflection, a nested type that is defined using these languages includes the type parameters of all its enclosing types. 这使封闭类型的类型形参可在嵌套类型的成员定义中使用。This allows the type parameters of enclosing types to be used in the member definitions of a nested type. 有关详细信息,请参阅 MakeGenericType中的“嵌套类型”。For more information, see "Nested Types" in MakeGenericType.

    备注

    通过在动态程序集中触发代码或通过使用 Ilasm.exe (IL Assembler) 定义的嵌套类型不需要包括其封闭类型的类型参数;然而,如果不包括,类型参数就不会在嵌套类的范围内。A nested type that is defined by emitting code in a dynamic assembly or by using the Ilasm.exe (IL Assembler) is not required to include the type parameters of its enclosing types; however, if it does not include them, the type parameters are not in scope in the nested class.

    有关详细信息,请参阅 MakeGenericType中的“嵌套类型”。For more information, see "Nested Types" in MakeGenericType.

返回页首Back to top

类库和语言支持Class Library and Language Support

.NET 在以下命名空间中提供了大量泛型集合类:.NET provides a number of generic collection classes in the following namespaces:

System 命名空间提供实现排序和等同性比较的泛型接口,还提供事件处理程序、转换和搜索谓词的泛型委托类型。Generic interfaces for implementing sort and equality comparisons are provided in the System namespace, along with generic delegate types for event handlers, conversions, and search predicates.

已将对泛型的支持添加到: System.Reflection 命名空间(以检查泛型类型和泛型方法)、 System.Reflection.Emit (以发出包含泛型类型和方法的动态程序集)和 System.CodeDom (以生成包括泛型的源图)。Support for generics has been added to the System.Reflection namespace for examining generic types and generic methods, to System.Reflection.Emit for emitting dynamic assemblies that contain generic types and methods, and to System.CodeDom for generating source graphs that include generics.

公共语言运行时提供了新的操作码和前缀来支持 Microsoft 中间语言 (MSIL) 中的泛型类型,包括 StelemLdelemUnbox_AnyConstrainedReadonlyThe common language runtime provides new opcodes and prefixes to support generic types in Microsoft intermediate language (MSIL), including Stelem, Ldelem, Unbox_Any, Constrained, and Readonly.

Visual C++、C# 和 Visual Basic 都对定义和使用泛型提供完全支持。Visual C++, C#, and Visual Basic all provide full support for defining and using generics. 有关语言支持的详细信息,请参阅 Visual Basic 中的泛型类型泛型简介Visual C++ 中的泛型概述For more information about language support, see Generic Types in Visual Basic, Introduction to Generics, and Overview of Generics in Visual C++.

返回页首Back to top

嵌套类型和泛型Nested Types and Generics

嵌套在泛型类型中的类型可取决于封闭泛型类型的类型参数。A type that is nested in a generic type can depend on the type parameters of the enclosing generic type. 公共语言运行时将嵌套类型看作泛型,即使它们不具有自己的泛型类型形参。The common language runtime considers nested types to be generic, even if they do not have generic type parameters of their own. 创建嵌套类型的实例时,必须指定所有封闭泛型类型的类型实参。When you create an instance of a nested type, you must specify type arguments for all enclosing generic types.

返回页首Back to top

TitleTitle 说明Description
.NET 中的泛型集合Generic Collections in .NET 介绍了 .NET 中的泛型集合类和其他泛型类型。Describes generic collection classes and other generic types in .NET.
用于控制数组和列表的泛型委托Generic Delegates for Manipulating Arrays and Lists 描述用于转换、搜索谓词以及要对数组或集合中的元素执行的操作的泛型委托。Describes generic delegates for conversions, search predicates, and actions to be taken on elements of an array or collection.
泛型接口Generic Interfaces 描述跨泛型类型系列提供通用功能的泛型接口。Describes generic interfaces that provide common functionality across families of generic types.
协变和逆变Covariance and Contravariance 描述泛型类型实参中的协变和逆变。Describes covariance and contravariance in generic type parameters.
常用的集合类型Commonly Used Collection Types 总结了 .NET 中集合类型(包括泛型类型)的特征和使用方案。Provides summary information about the characteristics and usage scenarios of the collection types in .NET, including generic types.
何时使用泛型集合When to Use Generic Collections 描述用于确定何时使用泛型集合类型的一般规则。Describes general rules for determining when to use generic collection types.
如何:使用反射发出定义泛型类型How to: Define a Generic Type with Reflection Emit 解释如何生成包括泛型类型和方法的动态程序集。Explains how to generate dynamic assemblies that include generic types and methods.
Visual Basic 中的泛型类型Generic Types in Visual Basic 为 Visual Basic 用户描述泛型功能,包括有关使用和定义泛型类型的帮助主题。Describes the generics feature for Visual Basic users, including how-to topics for using and defining generic types.
泛型介绍Introduction to Generics 为 C# 用户概述定义和使用泛型类型。Provides an overview of defining and using generic types for C# users.
Visual C++ 中的泛型概述Overview of Generics in Visual C++ 为 C++ 用户描述泛型功能,包括泛型和模板之间的差异。Describes the generics feature for C++ users, including the differences between generics and templates.

参考Reference

System.Collections.Generic

System.Collections.ObjectModel

System.Reflection.Emit.OpCodes

返回页首Back to top