C#知识学习-019(泛型类型约束关键字)

C#泛型类型约束详解

目录

1.new约束

1.1 概念

1.2 通俗解释

1.3 举例

2.where泛型类型约束

2.1 基本语法

2.2 常用的约束类型

2.2.1 接口约束(必须实现某个接口)

2.2.2 基类约束(必须是某个类的子类)

2.2.3 引用类型约束 (class)

2.2.4 值类型约束 (struct)

2.2.5 无参数构造函数约束 (new())

2.2.6 非托管类型约束 (unmanaged)


1.new约束

1.1 概念

new约束就像给泛型类型参数设置了一个规则:​"这个类型 T 必须能够用 new T()的方式创建对象"​

  • 什么是泛型约束?泛型约束就是​​给泛型类型参数设置限制条件​​,告诉编译器这个类型参数必须满足什么要求。

  • 什么是泛型?泛型允许我们编写可以处理不同数据类型的类或方法,而无需为每个类型重复编写代码。

  • 什么是约束?约束是限制泛型类型参数可以为什么类型的一种方式。例如,我们可以要求类型参数必须实现某个接口或继承某个类。

  • new约束它要求类型参数必须有一个公共的无参数构造函数。这样我们就可以在泛型类中创建该类型的实例。若要使用 new 约束,类型不能是抽象的。

1.2 通俗解释

你开了一家​​玩具工厂​​,但这个工厂很特别:

// 你的玩具工厂规定:只能生产那些"一按按钮就能出来"的玩具
class 玩具工厂<T> where T : new()
{
    public T 生产玩具()
    {
        return new T(); // 就像按一下按钮,玩具就出来了
    }
}

符合要求的玩具:​

  • 洋娃娃(拆开包装就能玩)

  • 球类(拿出来就能玩)

class 洋娃娃 { }    // 可以直接 new 洋娃娃()
class 球类 { }    // 可以直接 new 球类()

不符合要求的玩具:​

  • 需要组装的模型飞机(需要先拼装)

  • 抽象的概念(比如"快乐",无法具体制造)

class 模型飞机 
{ 
    public 模型飞机(string 说明书) { } // 需要说明书才能组装
}

abstract class 快乐 { } // "快乐"是抽象概念,无法制造

1.3 举例

// 使用示例
Factory<Product> factory = new Factory<Product>();
Product product = factory.CreateInstance();
Console.WriteLine(product.Name);

// 简单的类
public class Product
{
    public string Name { get; set; } = "Default";
    
    // 这就是构造函数 - 方法名与类名相同,没有返回类型
    // 构造函数​​不需要传入任何值​​,所以是无参数构造函数
    public Product()
    {
        Console.WriteLine("Product created");
    }
}

// 使用 new() 约束的泛型类
public class Factory<T> where T : new()
{
    public T CreateInstance()
    {
        return new T();  // 这里可以安全使用 new T()
    }
}

补充:

  • "无参数"指的是构造函数​​不需要传入任何值
// 无参数构造函数 - 创建时不需要传值
public class Product
{
    public Product()  // 括号里是空的,没有参数
    {
        // 创建对象时:Product p1 = new Product();
    }
}

// 有参数构造函数 - 创建时需要传值
public class Product
{
    public Product(string name)  // 括号里有参数
    {
        // 创建对象时:Product p2 = new Product("iPhone"); 
    }
}
  • 定义泛型工厂类

    • Factory<T>是一个​​泛型类​​,其中的 T可以是任何类型

    • where T : new()是​​约束​​,意思是:"T 必须能用 new T() 来创建"

    • 因为有了这个约束,在 CreateInstance()方法中写 new T()是安全的

  • 执行流程

    • 创建工厂​​:Factory<Product> factory = new Factory<Product>();

      • 这里把 Product类型传给 Factory<T>的 T

      • 编译器检查 Product是否符合 new()约束(确实符合,因为 Product 有无参数构造函数)

    • ​创建产品​​:Product product = factory.CreateInstance();

      • 调用 factory.CreateInstance(),方法内部执行 return new T();此时 T是 Product,所以相当于 new Product()

      • 执行 Product 的构造函数,输出 "Product created",返回一个 Product 对象

补充:

​当你有多个约束时,new()必须放在最后面​​。

举例:

public class ItemFactory2<T>
    where T : IComparable, new()  // new() 在最后
{  }

为什么有这个规则?

这就像写地址时的顺序:​​国家 → 城市 → 街道 → 门牌号​

在约束中,顺序是:​​基类/接口 → 构造函数约束​

补充:

IComparable是一个接口,它让对象能够​​比较大小​​。

对于具体类型,可以直接比较:

int a = 5, b = 3;
bool result = a > b;

​泛型类型 T​ 在编译时是未知的:

public class SortingFactory<T> where T : new()
{
    public void SortItems(T[] items)
    {
        // 这里不能直接比较,因为不知道T有没有比较能力
        // if (items[0] > items[1])  // 编译错误!
        // Array.Sort(items);        // 编译错误!
    }
}

​为了让编译器知道 T可以比较​​:

public class SortingFactory<T> where T : IComparable, new()
{
    public void SortItems(T[] items)
    {
        // 现在可以了,因为编译器知道T实现了IComparable
        Array.Sort(items);  // 可以排序
    }
    
    public T GetMax(T a, T b)
    {
        // 可以比较大小
        return a.CompareTo(b) > 0 ? a : b;
    }
}

2.where泛型类型约束

2.1 基本语法

public class 类名<T> where T : 约束条件
{
    // 类内容
}

2.2 常用的约束类型

2.2.1 接口约束(必须实现某个接口)

// T 必须实现 IComparable<T> 接口
public class Sorter<T> where T : IComparable<T>
{
    public void Sort(T[] items)
    {
        // 这里可以调用 items[i].CompareTo() 方法
        // 因为 T 肯定有 CompareTo 方法
    }
}

2.2.2 基类约束(必须是某个类的子类)

// T 必须是 Animal 或其子类
public class Zoo<T> where T : Animal
{
    public void MakeSound(T animal)
    {
        animal.Eat(); // 可以调用 Animal 的方法
    }
}

2.2.3 引用类型约束 (class)

// T 必须是引用类型(类、接口、委托等)
public class ReferenceContainer<T> where T : class
{
    public T Item { get; set; }
}

2.2.4 值类型约束 (struct)

// T 必须是值类型(int, double, struct 等)
public class ValueContainer<T> where T : struct
{
    public T Value { get; set; }
}

2.2.5 无参数构造函数约束 (new())

// T 必须有无参数的构造函数
public class Factory<T> where T : new()
{
    public T CreateInstance()
    {
        return new T(); // 可以创建实例
    }
}

2.2.6 非托管类型约束 (unmanaged)

// T 必须是非托管类型(基本数值类型、枚举、指针等)
public unsafe class UnmanagedProcessor<T> where T : unmanaged
{
    public void Process(T* pointer)
    {
        // 可以安全地进行指针操作
    }
}

学到了这里,咱俩真棒,记得按时吃饭(万圣夜快乐噢~)

【本篇结束,新的知识会不定时补充】

感谢你的阅读!如果内容有帮助,欢迎 ​​点赞❤️ + 收藏⭐ + 关注​​ 支持! 😊

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值