C#泛型约束完整示例(含全部约束类型 + 注释)

C# 7.3 保留了所有主流泛型约束,仅小幅优化语法兼容,下面分基础约束、组合约束、特殊约束逐一实现,代码可直接运行,附带详细说明。

一、先回顾泛型约束分类

  1. 基类约束类名 要求泛型参数必须继承自该类
  2. 接口约束接口名 要求实现指定接口
  3. 引用类型约束class 必须是引用类型(类、接口、数组、委托)
  4. 值类型约束struct 必须是值类型(结构体、枚举,不可为可空类型
  5. 无参数构造函数约束new() 必须拥有公共无参构造
  6. 组合约束:多个约束叠加,用 , 分隔
  7. 类型参数约束(裸类型约束)T : U 泛型参数继承另一个泛型参数

二、完整可运行代码(C# 7.3)

using System;

    /*
     * 定义:泛型约束指的就是声明泛型的时候指定一些约束条件,那么在使用的时候会自行进行约束条件的判断。
     * 
     * 举例:public struct Nullable<T> where T : struct
     * 
     * 常见的泛型约束:
     * 
     *      1、<T> where T : struct          指定类型必须是值类型
     *      2、<T> where T : class           指定类型必须是引用类型
     *      3、<T> where T : new()           指定类型必须有无参数的构造函数,如果有其他约束,则new()约束必须放到最后
     *      4、<T> where T : 类名约束         指定类型必须是某类或派生自某类,如果与其他接口共用,则放到接口前面;T要么是某类,要么是某类的子类或孙子类
     *      5、<T> where T : 接口约束         指定类型必须是实现一个或多个接口     
     *      6、<T> where T : 多泛型约束       指定类型必须是约束泛型或约束泛型的子类;也叫多类型占位符约束
     */
namespace GenericConstraintDemo
{
    #region 1. 准备测试基类、接口、结构体
    // 基类
    public class Animal
    {
        public virtual void Speak()
        {
            Console.WriteLine("动物发出声音");
        }
    }

    // 接口
    public interface IRunning
    {
        void Run();
    }

    // 继承基类+实现接口(用于约束测试)
    public class Dog : Animal, IRunning
    {
        public override void Speak()
        {
            Console.WriteLine("汪汪汪");
        }

        public void Run()
        {
            Console.WriteLine("小狗快速奔跑");
        }
    }

    // 结构体(值类型)
    public struct Point
    {
        public int X;
        public int Y;
    }

    // 带无参构造的普通类
    public class Person
    {
        public Person() { } // 无参构造

        public void SayHello()
        {
            Console.WriteLine("你好");
        }
    }
    #endregion

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("===== 1. 基类约束测试 =====");
            TestBaseClassConstraint<Dog>();

            Console.WriteLine("\n===== 2. 接口约束测试 =====");
            TestInterfaceConstraint<Dog>();

            Console.WriteLine("\n===== 3. 引用类型约束(class)测试 =====");
            TestRefTypeConstraint<Dog>();

            Console.WriteLine("\n===== 4. 值类型约束(struct)测试 =====");
            TestValueTypeConstraint<Point>();

            Console.WriteLine("\n===== 5. 无参构造函数约束(new())测试 =====");
            TestNewConstraint<Person>();

            Console.WriteLine("\n===== 6. 多约束组合测试 =====");
            TestMultiConstraint<Dog>();

            Console.WriteLine("\n===== 7. 裸类型参数约束测试 =====");
            TestNakedTypeConstraint<Animal, Dog>();
        }

        #region 1. 基类约束:T 必须继承自 Animal
        /// <summary>
        /// 约束:T 是 Animal 或其子类
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public static void TestBaseClassConstraint<T>() where T : Animal
        {
            T animal = Activator.CreateInstance<T>();
            animal.Speak();
        }
        #endregion

        #region 2. 接口约束:T 必须实现 IRunning 接口
        public static void TestInterfaceConstraint<T>() where T : IRunning
        {
            T obj = Activator.CreateInstance<T>();
            obj.Run();
        }
        #endregion

        #region 3. 引用类型约束:T 必须是 类/接口/数组 等引用类型
        public static void TestRefTypeConstraint<T>() where T : class
        {
            Console.WriteLine($"当前泛型类型 {typeof(T)} 是引用类型");
        }
        #endregion

        #region 4. 值类型约束:T 必须是 结构体/枚举(值类型)
        public static void TestValueTypeConstraint<T>() where T : struct
        {
            Console.WriteLine($"当前泛型类型 {typeof(T)} 是值类型");
        }
        #endregion

        #region 5. 无参构造函数约束:T 必须有公共无参构造
        /// <summary>
        /// 注意:new() 约束**必须放在所有约束最后**
        /// </summary>
        public static void TestNewConstraint<T>() where T : new()
        {
            T person = new T();
            if (person is Person p)
            {
                p.SayHello();
            }
        }
        #endregion

        #region 6. 多约束组合(C#7.3 完全支持)
        /// <summary>
        /// 组合规则:基类/接口 → class/struct → new()
        /// 约束顺序不能乱
        /// </summary>
        public static void TestMultiConstraint<T>() where T : Animal, IRunning, new()
        {
            T obj = new T();
            obj.Speak();
            obj.Run();
        }
        #endregion

        #region 7. 裸类型参数约束(T 必须继承自 U)
        /// <summary>
        /// 语法:T : U  要求 T 是 U 的子类/实现类
        /// </summary>
        public static void TestNakedTypeConstraint<U, T>() where T : U
        {
            Console.WriteLine($"T({typeof(T)}) 继承自 U({typeof(U)})");
        }
        #endregion
    }
}

三、运行输出结果

===== 1. 基类约束测试 =====
汪汪汪

===== 2. 接口约束测试 =====
小狗快速奔跑

===== 3. 引用类型约束(class)测试 =====
当前泛型类型 GenericConstraintDemo.Dog 是引用类型

===== 4. 值类型约束(struct)测试 =====
当前泛型类型 GenericConstraintDemo.Point 是值类型

===== 5. 无参构造函数约束(new())测试 =====
你好

===== 6. 多约束组合测试 =====
汪汪汪
小狗快速奔跑

===== 7. 裸类型参数约束测试 =====
T(GenericConstraintDemo.Dog) 继承自 U(GenericConstraintDemo.Animal)

四、C# 7.3 泛型约束核心规则(重点必记)

1. 约束书写固定顺序(报错高频点)

where T : [基类/接口], [class/struct], [new()]
  1. 第一部分:基类(只能1个)+ 接口(多个)
  2. 第二部分:class / struct(二选一,不能同时写)
  3. 第三部分:new() 无参构造(永远放最后

2. 关键限制说明

  • struct 约束:不包含可空类型(如 int? 无法通过)
  • new():要求公共无参构造,私有构造/有参构造都会编译报错
  • 基类约束只能写一个,接口可以写多个,用逗号分隔
  • C# 7.3 对比旧版本:无语法删减,仅优化了泛型委托、元组、默认值等配套语法,约束逻辑完全一致

3. 编译报错示例(避坑)

  1. 顺序错误:where T : new(), Animal → 编译报错
  2. 同时写 class + struct:where T : class, struct → 编译报错
  3. 传入不符合约束的类型:
    TestValueTypeConstraint<Dog>(); // Dog是类,不是struct → 报错
    

五、拓展:泛型方法 + 泛型类 双重示例

日常开发更多用泛型类,补充示例:

// 泛型类 + 组合约束
public class Repository<T> where T : Animal, new()
{
    public T CreateInstance()
    {
        return new T();
    }

    public void ShowInfo()
    {
        var t = CreateInstance();
        t.Speak();
    }
}

// 调用
var repo = new Repository<Dog>();
repo.ShowInfo();
posted @ 2026-05-26 16:24  人生就是修炼  阅读(36)  评论(0)    收藏  举报