c#泛型约束

本文介绍了C#中泛型约束的概念和作用,通过代码示例展示了如何在泛型方法中使用约束,确保传入参数为指定类及其子类。同时提到了泛型约束的应用场景,包括但不限于泛型方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.泛型约束的使用

泛型约束的作用
在一个泛型方法或者说泛型接口中,传入的泛型是不确定的,但是在方法体中,我们传入一个实体,要在代码块中获取实体的各种属性如:姓名、性别等,但是问题来了,由于我们的类型是在调用的时候确定的,因此在写泛型方法或接口代码的时候我们是不确定入参类型,所以就需要一个东西来确定入参有那些属性,由此 泛型约束就冒出来了,当然 为了更好的理解 下面有代码解释—以泛型方法为例:
首先我们定义一个动物类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace StudyComm.ClassFolder
{
    /// <summary>
    /// 动物
    /// </summary>
    public class AnimalClass
    {
        /// <summary>
        /// 动物种类
        /// </summary>
        public string AnimalType { get; set; }

    }
}

 然后再定义一个鸟类  和狗类 继承自动物

public class BirdClass : AnimalClass
{
    /// <summary>
    /// 鸟类名字
    /// </summary>
    public int BirdName { get; set; }

}
public class DogClass : AnimalClass
{
    /// <summary>
    /// 狗的种类
    /// </summary>
    public string DogType { get; set; }
}

我们再定义一个人类

/// <summary>
/// 人类
/// </summary>
public class HumanClass
{
    /// <summary>
    /// 名字
    /// </summary>
    public string Name { get; set; }
    /// <summary>
    /// 国籍
    /// </summary>
    public string Nationality { get; set; }
}

再来一个中国人和日本人

/// <summary>
/// 定义一个中国人的类,并继承人类
/// </summary>
public class ChineseClass : HumanClass
{
    /// <summary>
    /// 身份证
    /// </summary>
    public string IDCard { get; set; }
}
/// <summary>
/// 定义一个日本人
/// </summary>
public class JapaneseClass : HumanClass
{
	//这里面我就不加属性 因为日本人是直接继承人类  所以也具有名字和种类
}

在写好了类之后 ,我来写几个方法 在每个方法中 使用泛型约束 规定在调用的时候传入的参数必须为指定类及其子类

public class FunClass
{
    /// <summary>
    /// 用于展示中国人的名字
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="Type"></param>
    public static void ShowHuman<T>(T Type) where T : HumanClass//泛型约束为  HumanClass类,表示只能传入人类  以及其子类
    {
        Console.WriteLine($"这个人是一个{Type.Name},他的国籍是{Type.Nationality}");
    }
    public static void ShowBirdType<T>(T Type) where T : AnimalClass//泛型约束为  AnimalClass类,表示只能传入动物类  以及其子类
    {
        Console.WriteLine($"这个动物的种类是{Type.AnimalType}");
    }
}

我们在方法里实例化两个人 一个中国人,一个日本人

//实例化一个中国人,日本人
ChineseClass chinese = new ChineseClass() { Name="小明",Nationality="中国"};//中国人
JapaneseClass human = new JapaneseClass() { Name = "小岛秀夫", Nationality = "日本" };//日本人

上面实例化的两个人都是继承自HumanClass类 所以在调用的时候

 //我们在调用的时候<>中可以指定类型为HumanClass
 FunClass.ShowHuman<HumanClass>(chinese);//传入中国人
 FunClass.ShowHuman<HumanClass>(human);//传入日本人
 //当然  我们也可以把具体的类指定进去
 FunClass.ShowHuman<ChineseClass>(chinese);//传入中国人
 FunClass.ShowHuman<JapaneseClass>(human);//传入日本人
 //同时  我们也可以简写为
 FunClass.ShowHuman(chinese);//传入中国人
 FunClass.ShowHuman(human);//传入日本人
  • 以上三种写法都是可以的
  • 但是 如果我们实例化个鸟和狗之后,把鸟 或者狗传入ShowHuman方法 那么就会报错

 

 

  • 由于我们ShowHuman方法约束了传入的只能是HumanClass及其子类,传入的dog 是无法转化为Human等类型,故此报错
  • 泛型约束的可作用场景

  • 上面只是泛型方法的约束使用,但是泛型可用的地方总共有六种
名称描述
new()类型参数必须具有无参数的公共构造函数。当与其他约束一起使用时,new() 约束必须最后指定。
接口类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的。
基类类型参数必须是指定的基类或派生自指定的基类。
U为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。这称为裸类型约束。
结构类型参数必须是值类型。可以指定除 Nullable 以外的任何值类型
类型参数必须是引用类型,包括任何类、接口、委托或数组类型

例子:

namespace StudyComm.Generic
{
    class GenericConstraint<T> where T : GenericInterFace<T>//接口约束GenericInterFace为一个泛型接口
    {
    }
    class ClassOrStructureConstraint<T, A>//类或结构约束
    where T : HumanClass
    where A : AnimalClass
    {

    }
    public class ConstructorConstraint<T> where T: IComparable, new()//构造函数约束
    {
        //裸类型约束,当具有自己的类型参数的成员函数需要将该参数约束为包含类型的类型参数时可使用
        void UConstraint<U>(List<U> list) where U : T
        { }
    }

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值