C# 的泛型参数约束
介绍
泛型在 C# 2.0 版和 CLR(通用语言运行时)中成为其中的一部分。它引入了类型参数的概念,允许您设计类和方法,将一个或多个类型的指定推迟到客户端代码声明和实例化类或方法为止。
在本指南中,我们将介绍如何创建这样的类和方法,并讨论 CLR 对实现施加的约束。
泛型
示例如下:
public class GenericArray(T)
{
public void Summarize(T input);
}
这些类和方法结合了三个不同的特点:
- 可重用性
- 类型安全
- 效率
泛型通常与集合以及对其执行操作的方法结合使用。
引入了一个名为System.Collections.Generic的新命名空间,其中包含几个新的基于泛型的集合类。您还可以为自己的解决方案创建自定义泛型类型和方法,并自定义类型安全且高效的设计模式。
参数
类型参数是客户端在创建泛型类型的实例时指定的特定类型的占位符。泛型类不能按原样使用,因为它只是该类型的蓝图。我们需要声明,然后通过在尖括号或<>之间指定类型参数来实例化构造类型。此类型必须是编译器可识别的。您可以创建任何类型的实例 - 没有限制。
例如:
GenericArray<int> myFloatGenericArray = new GenericArray<int>();
GenericArray<string> myFloatGenericArray = new GenericArray<string>();
上面的示例显示了具有int和string类型的 **GenericArray 蓝图的实例化。在每种情况下,参数T` 在运行时都会被类型参数替换,这使我们能够仅使用一个类定义来创建类型安全且高效的对象。
命名的一些规则:
- 泛型类型参数应该具有描述性名称。
- 在描述性类型参数前面加上T前缀,如下所示:<TConfigurationItem>
约束
约束是告知编译器类型参数必须具备的功能的特定规则。如果没有这些,类型参数可以是任何类型。默认情况下,编译器假定System.Object类,它是任何 .NET 类型的最终基类。您可以说它是基类的动力。当客户端代码想要实例化具有任何约束都不允许的类型时,它将导致编译时错误。为了定义约束,我们需要使用where关键字,它始终基于上下文。
总共有八种约束类型:
- 其中 T : struct:参数必须是除Nullable<T>之外的值类型。
- 其中 T : class:参数必须是引用类型,它适用于类、接口和委托,甚至数组。
- 其中 T:notnull:参数必须不可空。
- 其中 T:非托管:参数必须是非托管类型,又名指针和不安全代码。
- 其中 T:基类:参数必须从类型的基类或基类本身派生。
- 其中 T : new():参数必须有一个无参数的构造函数,它是公共的。
- 其中 T:接口:参数必须是或实现指定的接口。
- 其中 T : U:参数必须是或源自为 U 提供的参数。
您需要知道,其中一些约束是互斥的。值类型必须具有可访问的无参数构造函数。例如,struct约束隐含new()约束,而new()约束不能与 struct 约束组合使用。
为什么要使用约束?
对特定类型参数强制约束允许您增加允许的操作和方法调用的数量,这些操作和方法调用受约束类型及其继承层次结构中的类型支持。泛型类和方法的设计意味着您将对泛型成员执行任何操作,而不仅仅是简单的赋值、实例化或调用 System.Object基类不支持的方法。您需要约束来强制执行限制。一个非常实际的例子是当您使用基类约束来告诉编译器只有特定类型才会用作任何派生类的类型参数时。此保证允许编译器允许在泛型类中调用该类型的方法。
一个简单的例子
using System;
using System.Collections.Generic;
namespace cnstraints
{
class GenericClass<T> where T : class
{
private readonly T _field;
public GenericClass(T value){
this._field = value;
}
public T genericMethod(T parameter) {
Console.WriteLine($"The type of parameter we got is: {typeof(T)} and value is: {parameter}");
Console.WriteLine($"The return type of parameter is: {typeof(T)} and value is: {this._field}");
return this._field;
}
}
class Program
{
static void Main(string[] args)
{
GenericClass<string> myGeneric = new GenericClass<string>("Hello World");
myGeneric.genericMethod("string");
Console.ReadKey();
}
}
}
调用以下代码将得到此输出。
The type of parameter we got is: System.String and value is: string
The return type of parameter is: System.String and value is: Hello World
让我们研究一下这里发生了什么。我们有一个具有where T : class约束的泛型类。这意味着参数必须是引用类型,并且适用于类、接口和委托,甚至数组。我们还有一个泛型方法,它接受单个参数并输出一些字符串。
结论
在本指南中,您熟悉了泛型及其约束的概念。我们知道泛型是何时诞生的,以及这种数据类型存在哪些类型的约束。这只是触及了这个主题的表面,当您深入挖掘它以尝试为您的问题找到通用解决方案时,它可能会变成一个兔子洞。当您想要走这条路时,您应该考虑到这一点。例如,一个单一用途的简单应用程序可以在没有任何通用实现的情况下存在,但在大型企业应用程序中,考虑这种功能可能是一个好主意。决定权在您手中。
我希望这篇文章对您有所帮助,希望您能找到自己想要的东西。如果您喜欢本指南,请点赞!
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~