【笔记】C# 泛型约束

作者:@哈桑c(CSDN平台)
专栏:全栈开发自学记录

文章目录

  • 什么是泛型约束?
  • 示例代码
  • 1、值类型约束(: struct)
  • 2、引用类型约束(: class)
  • 3、可为空引用类型约束(: class?)
  • 4、不可为空约束(: notnull)
  • 5、基方法约束(: default)
  • 6、非托管类型约束(: unmanaged)
  • 7、构造函数约束(: new())
  • 8、基类名约束(: <基类名>)
  • 9、可为空基类名约束(: <基类名>?)
  • 10、接口类型约束(:<接口名称>)
  • 11、可为空接口类型约束(:<接口名称>?)
  • 12、自定义约束(: U)

什么是泛型约束?

泛型约束就是告知编译器类型参数必须具备的功能。 在没有任何约束的情况下,类型参数可以是任何类型。 编译器只能假定 System.Object 的成员,它是任何 .NET 类型的最终基类。当分配给泛型的类型参数不满足约束的类型时,编译器会报出 Compiler Error CS0452 的错误。在 C# 中允许使用 where 上下文关键字指定约束。

【笔记】C# 泛型约束_第1张图片

示例代码

首先以一段简单的实现增加与设置数组元素的程序作为示例,借此讨论泛型类型参数的约束。同时也方便大家直接复制示例代码,然后对本文中提出的约束类型进行功能测试,辅助大家更好的理解。

代码示例

using System;
using System.Collections.Generic;

public class MyGenericList<T>
{
    private List<T> myList;

    public MyGenericList()
    {
        myList = new List<T> { };
    }

    // 增加元素
    public void AddElement(T value)
    {
        myList.Add(value); 
    }

    // 删除元素
    public void RemoveElement(int index)
    {
        myList.RemoveAt(index);
    }

    // 更改元素
    public void ChangeElement(int index, T value)
    {
        myList[index] = value;
    }

    // 查找元素
    public T GetElement(int index)
    {
        return myList[index];
    }
}

1、值类型约束(: struct)

where T : struct 表示类型参数必须是不可为 null 的值类型。

代码示例:

// 值类型约束
public class MyGenericList<T> where T : struct
{
	// 类成员... 
}

由于所有值类型都具有可访问的无参数构造函数,因此 struct 约束也表示 new() 约束,所以 struct 约束不能与 new() 约束和 unmanaged 约束一起使用。

2、引用类型约束(: class)

where T : class 表示类型参数必须是的引用类型。

代码示例:

// 引用类型约束
public class MyGenericList<T> where T : class
{
	// 类成员... 
}

此约束还应用于任何类、接口、委托或数组类型。 在可为 null 的上下文中,T 必须是不可为 null 的引用类型。

3、可为空引用类型约束(: class?)

where T : class? 表示类型参数必须是可为 null 或不可为 null 的引用类型。

代码示例:

// 引用类型约束
public class MyGenericList<T> where T : class?
{
	// 类成员... 
}

此约束还应用于任何类、接口、委托或数组类型。

4、不可为空约束(: notnull)

where T : notnull 表示类型参数必须是不可为 null 的类型。

代码示例:

// 引用类型约束
public class MyGenericList<T> where T : notnull
{
	// 类成员... 
}

参数可以是不可为 null 的引用类型,也可以是不可为 null 的值类型。

5、基方法约束(: default)

where T : default 表示重写方法或提供显式接口实现时,如果需要指定不受约束的类型参数,此约束可解决歧义。

代码示例:

// 引用类型约束
public class MyGenericList<T> where T : default
{
	// 类成员... 
}

default 约束表示基方法,但不包含 class 或 struct 约束。点击了解更多 default 约束。

6、非托管类型约束(: unmanaged)

where T : unmanaged 表示类型参数必须是不可为 null 的非托管类型。

代码示例:

// 引用类型约束
public class MyGenericList<T> where T : unmanaged
{
	// 类成员... 
}

unmanaged 约束也表示 struct 约束,且不能与 struct 约束或 new() 约束结合使用。

7、构造函数约束(: new())

where T : new() 表示类型参数必须具有公共无参数构造函数。

代码示例:

// 引用类型约束
public class MyGenericList<T> where T : new()
{
	// 类成员... 
}

当构造函数约束与其他约束一起使用时,new() 约束必须最后指定。 new() 约束不能与 struct 和 unmanaged 约束结合使用。

8、基类名约束(: <基类名>)

where T :<基类名> 表示类型参数必须是指定的基类或派生自指定的基类。

代码示例:

// 引用类型约束
public class MyGenericList<T> where T :<基类名>
{
	// 类成员... 
}

在可为 null 的上下文中,T 必须是从指定基类派生的不可为 null 的引用类型。

9、可为空基类名约束(: <基类名>?)

where T :<基类名>? 表示类型参数必须是指定的基类或派生自指定的基类。

代码示例:

// 引用类型约束
public class MyGenericList<T> where T :<基类名>?
{
	// 类成员... 
}

在可为 null 的上下文中,T 可以是从指定基类派生的可为 null 或不可为 null 的类型。

10、接口类型约束(:<接口名称>)

where T :<接口名称> 表示类型参数必须是指定的接口或实现指定的接口。

代码示例:

// 引用类型约束
public class MyGenericList<T> where T :<接口名称>
{
	// 类成员... 
}

可指定多个接口约束。 约束接口也可以是泛型。 在的可为 null 的上下文中,T 必须是实现指定接口的不可为 null 的类型。

11、可为空接口类型约束(:<接口名称>?)

where T :<接口名称>? 表示类型参数必须是指定的接口或实现指定的接口。

代码示例:

// 引用类型约束
public class MyGenericList<T> where T :<接口名称>?
{
	// 类成员... 
}

可指定多个接口约束。 约束接口也可以是泛型。 在可为 null 的上下文中,T 可以是可为 null 的引用类型、不可为 null 的引用类型或值类型。 T 不能是可为 null 的值类型。

12、自定义约束(: U)

where T : U 表示为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。

代码示例:

// 引用类型约束
public class MyGenericList<T> where T : U
{
	// 类成员... 
}

在可为 null 的上下文中,如果 U 是不可为 null 的引用类型,T 必须是不可为 null 的引用类型。 如果 U 是可为 null 的引用类型,则 T 可以是可为 null 的引用类型,也可以是不可为 null 的引用类型。

你可能感兴趣的:(全栈开发自学记录,c#,开发语言,.net,微软,.netcore)