在《C#高级编程之泛型(一):初识泛型》一文中简单介绍了一下泛型约束,本文将深入探究泛型约束。
1.不可为null的值类型:where T : struct
public static void GenericStruct<T>(T t) where T : struct
{ }
类型参数必须是不可为null的值类型。
2.不可为null的引用类型:where T : class
public static void GenericClass<T>(T t) where T : class
{ }
在C#8.0以上,类型参数必须是不可为null的引用类型,此约束可用于类、接口、委托或数组类型。
3.可为null的引用类型:where T : class?
public static void GenericClassNullable<T>(T t) where T : class?
{ }
类型参数可以是为null或不为null的引用类型,此约束可用于类、接口、委托或数组类型。(适用于C#8.0以上)
4.不可为null:where T : notnull
public static void GenericNotnull<T>(T t) where T : notnull
{ }
类型参数必须是不为null的类型,引用类型或值类型都可以。(适用于C#8.0以上)
5.非托管类型:where T : unmanaged
public static void GenericUnmanaged<T>(T t) where T : unmanaged
{ }
类型参数必须是不可为null、非托管类型。
6.公共无参构造函数:where T : new()
public static void GenericNew<T>(T t) where T : new()
{ }
/// <summary>
/// 没有无参构造函数的类
/// </summary>
public class CtorParam
{
public CtorParam(int num) { }
}
/// <summary>
/// 具有非公共无参构造函数的类
/// </summary>
public class ProtectedCtorNoParam
{
protected ProtectedCtorNoParam() { }
}
/// <summary>
/// 具有默认的无参构造函数的类
/// </summary>
public class CtorNoParam { }
类型参数必须具有公共无参构造函数。没有无参构造函数或者仅有私有或受保护的无参构造函数的类作为参数编译器直接报错。
7.指定不可为null的类或派生类:where T : <BaseClass>
public static void GenericBaseClass<T>(T t) where T : RichPeople
{ }
/// <summary>
/// 有钱人
/// </summary>
public class RichPeople
{
/// <summary>
/// 名字
/// </summary>
public string Name { get; set; }
}
/// <summary>
/// 马化云
/// </summary>
public class MHY : RichPeople { }
/// <summary>
/// 我
/// </summary>
public class Me { }
}
类型参数必须是指定的类型或其派生类。C#8.0以上,T必须是不可为null的类型。
8.指定可为null的类或派生类:where T : <BaseClass>?
public static void GenericBaseClassNullable<T>(T t) where T : RichPeople?
{ }
类型参数必须是指定的类型或其派生类。C#8.0以上,T可以是为null的类型,也可以是不为null的类型。
9.指定不可为null的接口或实现指定接口:where T : <Interface>
public static void GenericInterface<T>(T t) where T : ILanguage
{ }
public class Chinese : ILanguage { }
public class China { }
类型参数必须是指定的接口或实现指定接口。C#8.0以上,T必须是不可为null的类型。
10.指定可为null的接口或实现指定接口:where T : <Interface>?
public static void GenericInterfaceNullable<T>(T t) where T : ILanguage?
{ }
类型参数必须是指定的接口或实现指定接口。C#8.0以上,T可以是为null的类型,也可以是不为null的类型。
11.指定泛型类型:where T : U
public static void GenericGeneric<T, U>(T t) where T : U
{ }
类型参数必须是指定的泛型类型,本质上也是类约束,区别是约束的类也是泛型。
此外还有委托约束(where TDelegate : System.Delegate)、枚举约束(where T : System.Enum)等。
常用的约束有struct、class、new()、类约束、接口约束。
public static void GenericMulti<T>() where T : class, new()
{ }
类型参数必须同时满足多个约束。上诉代码,必须是引用类型,且具有公共无参构造函数!
①由于所有值类型都具有公共的无参构造函数,所以struct不能和new()约束一起使用。
②由于非托管类型只能是值类型,所以unmanaged约束不能和struct、new()约束一起使用。
③new()约束必须其他约束的后面。
④类约束必须在其他约束之前,因此不可同时指定多个类约束。
⑤上诉所有可空类型的约束,都是在C#8.0新增可空引用类型后诞生的,需要将项目Nullable设置为enable或者添加nullable注释后才能使用可空引用类型,不太常用。
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<!--允许可空引用类型-->
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
#nullable enable
ILanguage? language = null;
#nullable restore
结语
写之前没想到泛型约束能写这么多,本来还想研究一下泛型协变和逆变,太多了,就放在下篇吧!
版权声明:本文由不落阁原创出品,转载请注明出处!
广告位
暂无评论,大侠不妨来一发?
跟不落阁,学DOTNET!
广告位