前言

        本文系统介绍了面向对象编程(OOP)的三大核心特性:封装通过私有字段和公共属性保护数据安全;继承实现代码复用;多态允许子类重写父类方法。同时详细讲解了面向切面编程(AOP)的概念,它通过切面特性(如日志、性能监控)与核心业务逻辑解耦,演示了基于特性+反射的AOP实现方式,并与工业级AOP框架进行对比。文章通过交通工具的完整示例,展示了OOP三大特性与AOP的结合应用,最后还补充了泛型约束、设计模式等进阶内容,为开发者提供了全面的编程范式指导。

对象编程(OOP)

        面向对象编程(OOP)的三大核心特性:封装、继承和多态

        通过一个贴近实际的示例(以 “交通工具” 为场景)来清晰展示这三个特性的具体实现和应用。

一、OOP核心概念先理解

  • 封装:将数据(字段)和操作数据的方法封装在类中,通过访问修饰符(如 private/public)控制外部访问,只暴露必要的接口。
  • 继承:子类继承父类的属性和方法,实现代码复用,同时可扩展或重写父类功能。
  • 多态:同一行为在不同对象上表现出不同形态,C# 中主要通过虚方法重写(virtual/override)接口实现 实现。

二、完整代码实现

以下代码通过 “交通工具(父类)→ 汽车 / 电动车(子类)” 的层级,完整展示三大特性:

using System;

namespace OOP_Demo
{
    // ===================== 1. 封装:父类(交通工具) =====================
    /// <summary>
    /// 交通工具基类(封装核心属性和通用方法)
    /// </summary>
    public class Vehicle
    {
        // 私有字段(封装:外部无法直接访问)
        private string _brand; // 品牌
        private int _speed;    // 速度

        // 公共属性(封装:通过属性控制字段的读写,可添加校验逻辑)
        public string Brand
        {
            get => _brand; // 只读逻辑
            set
            {
                // 封装:对输入进行校验,保证数据合法性
                if (string.IsNullOrWhiteSpace(value))
                    throw new ArgumentException("品牌不能为空");
                _brand = value;
            }
        }

        public int Speed
        {
            get => _speed;
            set
            {
                if (value < 0)
                    throw new ArgumentOutOfRangeException("速度不能为负数");
                _speed = value;
            }
        }

        // 构造函数(封装:初始化私有字段)
        public Vehicle(string brand, int speed)
        {
            Brand = brand;
            Speed = speed;
        }

        // 虚方法(为多态做准备:允许子类重写)
        public virtual void Run()
        {
            Console.WriteLine($"{Brand} 以 {Speed} km/h 行驶(通用交通工具)");
        }

        // 封装的通用方法
        public void Stop()
        {
            Console.WriteLine($"{Brand} 已停止行驶");
            Speed = 0;
        }
    }

    // ===================== 2. 继承 + 多态:子类(汽车) =====================
    /// <summary>
    /// 汽车类(继承自Vehicle,扩展并重写父类方法)
    /// </summary>
    public class Car : Vehicle
    {
        // 子类新增属性(封装)
        private int _fuel; // 油量

        public int Fuel
        {
            get => _fuel;
            set
            {
                if (value < 0 || value > 100)
                    throw new ArgumentOutOfRangeException("油量需在0-100之间");
                _fuel = value;
            }
        }

        // 子类构造函数(必须调用父类构造函数)
        public Car(string brand, int speed, int fuel) : base(brand, speed)
        {
            Fuel = fuel;
        }

        // 多态:重写父类的Run方法
        public override void Run()
        {
            Console.WriteLine($"{Brand} 汽车(油量{Fuel}%)以 {Speed} km/h 行驶,耗油中...");
        }

        // 子类新增方法(封装)
        public void Refuel(int amount)
        {
            Fuel += amount;
            Console.WriteLine($"{Brand} 加油{amount}%,当前油量:{Fuel}%");
        }
    }

    // ===================== 2. 继承 + 多态:子类(电动车) =====================
    /// <summary>
    /// 电动车类(继承自Vehicle,扩展并重写父类方法)
    /// </summary>
    public class ElectricCar : Vehicle
    {
        // 子类新增属性(封装)
        private int _battery; // 电量

        public int Battery
        {
            get => _battery;
            set
            {
                if (value < 0 || value > 100)
                    throw new ArgumentOutOfRangeException("电量需在0-100之间");
                _battery = value;
            }
        }

        // 子类构造函数
        public ElectricCar(string brand, int speed, int battery) : base(brand, speed)
        {
            Battery = battery;
        }

        // 多态:重写父类的Run方法
        public override void Run()
        {
            Console.WriteLine($"{Brand} 电动车(电量{Battery}%)以 {Speed} km/h 行驶,耗电中...");
        }

        // 子类新增方法(封装)
        public void Charge(int amount)
        {
            Battery += amount;
            Console.WriteLine($"{Brand} 充电{amount}%,当前电量:{Battery}%");
        }
    }

    // ===================== 测试代码 =====================
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                // 1. 测试封装:通过属性控制数据合法性(错误示例)
                // var invalidCar = new Car("宝马", 120, -10); // 会抛出油量异常

                // 2. 实例化子类对象
                Car bmw = new Car("宝马", 120, 80);
                ElectricCar tesla = new ElectricCar("特斯拉", 150, 70);

                // 3. 测试继承:调用父类的Stop方法
                bmw.Run();       // 多态:执行Car重写的Run
                bmw.Refuel(10);  // 子类独有方法
                bmw.Stop();      // 继承自父类的方法

                Console.WriteLine("-----");

                tesla.Run();     // 多态:执行ElectricCar重写的Run
                tesla.Charge(20); // 子类独有方法
                tesla.Stop();    // 继承自父类的方法

                // 4. 多态的核心:父类引用指向子类对象
                Vehicle vehicle1 = new Car("奔驰", 110, 60);
                Vehicle vehicle2 = new ElectricCar("比亚迪", 130, 85);
                Console.WriteLine("-----");
                vehicle1.Run(); // 实际执行Car的Run
                vehicle2.Run(); // 实际执行ElectricCar的Run
            }
            catch (Exception ex)
            {
                Console.WriteLine("错误:" + ex.Message);
            }
        }
    }
}

三、代码关键解释

1. 封装的体现
  • 所有字段(如 _brand_fuel)都用 private 修饰,外部无法直接修改;
  • 通过 public 属性(如 BrandFuel)暴露访问,且属性的 set 方法中添加了数据校验(如油量不能为负),保证数据合法性;
  • 类中的方法(如 RefuelCharge)封装了具体的业务逻辑,外部只需调用方法,无需关心内部实现。
2. 继承的体现
  • CarElectricCar 都通过 : Vehicle 继承自父类 Vehicle
  • 子类自动拥有父类的属性(BrandSpeed)和方法(Stop),无需重复编写;
  • 子类构造函数通过 base(brand, speed) 调用父类构造函数,初始化父类的字段。
3. 多态的体现
  • 父类 Vehicle 中的 Run 方法用 virtual 标记,允许子类重写;
  • 子类 CarElectricCaroverride 重写 Run 方法,实现各自的行驶逻辑;
  • 核心:父类类型的变量(Vehicle vehicle1)可以指向子类对象(new Car(...)),调用 Run 时会执行子类的实现,而非父类的通用实现。

四、运行结果

宝马 汽车(油量80%)以 120 km/h 行驶,耗油中...
宝马 加油10%,当前油量:90%
宝马 已停止行驶
-----
特斯拉 电动车(电量70%)以 150 km/h 行驶,耗电中...
特斯拉 充电20%,当前电量:90%
特斯拉 已停止行驶
-----
奔驰 汽车(油量60%)以 110 km/h 行驶,耗油中...
比亚迪 电动车(电量85%)以 130 km/h 行驶,耗电中...

OOP总结

  1. 封装:核心是 “隐藏内部细节,暴露安全接口”,通过 private 字段 + public 属性 / 方法实现,保证数据安全和代码可控;
  2. 继承:核心是 “复用父类代码,扩展子类功能”,子类通过 : 父类 继承,需调用父类构造函数,可新增属性 / 方法;
  3. 多态:核心是 “同一行为,不同表现”,通过 virtual(父类)+ override(子类)实现,支持父类引用指向子类对象,提高代码灵活性。

这三个特性是 OOP 的核心,封装保证代码的安全性,继承保证代码的复用性,多态保证代码的扩展性,三者结合能写出高内聚、低耦合的优质代码。

AOP(面向切面编程)

一、先理解 AOP 核心概念

AOP(Aspect-Oriented Programming,面向切面编程)是对 OOP 的补充,核心思想是:

  • 核心业务逻辑(比如汽车行驶、充电)和通用横切逻辑(比如日志记录、性能监控、异常处理)分离;
  • 这些横切逻辑(如 “记录行驶日志”)就像一个 “切面”,可以动态植入到核心业务的执行流程中,无需修改核心代码。
  • C# 中实现 AOP 最常用的方式有两种:特性(Attribute)+ 反射(入门级)、第三方框架(如 Autofac.DynamicProxy、PostSharp)(工业级)。

二、结合 OOP 示例实现 AOP(特性 + 反射)

下面基于之前的 “交通工具” 示例,新增 AOP 功能:给 Run() 方法添加日志记录性能监控的切面逻辑,不修改原有核心代码。

1. 完整代码实现

csharp

运行

using System;
using System.Diagnostics;
using System.Reflection;

namespace OOP_AOP_Demo
{
    // ===================== 第一步:定义AOP切面特性 =====================
    /// <summary>
    /// 日志记录切面特性(标记在方法上,实现日志记录)
    /// </summary>
    [AttributeUsage(AttributeTargets.Method)]
    public class LogAttribute : Attribute
    {
        // 切面逻辑:执行方法前后记录日志
        public void ExecuteBefore(string methodName, object instance)
        {
            Console.WriteLine($"[日志] {DateTime.Now} - 开始执行 {instance.GetType().Name}.{methodName} 方法");
        }

        public void ExecuteAfter(string methodName, object instance)
        {
            Console.WriteLine($"[日志] {DateTime.Now} - 完成执行 {instance.GetType().Name}.{methodName} 方法");
        }
    }

    /// <summary>
    /// 性能监控切面特性(标记在方法上,统计方法执行耗时)
    /// </summary>
    [AttributeUsage(AttributeTargets.Method)]
    public class PerformanceAttribute : Attribute
    {
        private Stopwatch _stopwatch;

        // 切面逻辑:方法执行前启动计时器
        public void ExecuteBefore()
        {
            _stopwatch = Stopwatch.StartNew();
        }

        // 切面逻辑:方法执行后停止计时器,输出耗时
        public void ExecuteAfter(string methodName, object instance)
        {
            _stopwatch.Stop();
            Console.WriteLine($"[性能] {instance.GetType().Name}.{methodName} 执行耗时:{_stopwatch.ElapsedMilliseconds} ms");
        }
    }

    // ===================== 第二步:AOP切面执行器(核心) =====================
    /// <summary>
    /// AOP执行器:通过反射执行标记了切面特性的方法,并植入切面逻辑
    /// </summary>
    public static class AopExecutor
    {
        public static void ExecuteMethod(object instance, string methodName)
        {
            // 1. 获取目标方法
            MethodInfo method = instance.GetType().GetMethod(methodName);
            if (method == null)
            {
                throw new ArgumentException($"方法 {methodName} 不存在");
            }

            // 2. 提取方法上的切面特性
            var logAttr = method.GetCustomAttribute<LogAttribute>();
            var perfAttr = method.GetCustomAttribute<PerformanceAttribute>();

            // 3. 执行切面的“前置逻辑”
            logAttr?.ExecuteBefore(methodName, instance);
            perfAttr?.ExecuteBefore();

            try
            {
                // 4. 执行核心业务方法(原有OOP逻辑)
                method.Invoke(instance, null);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[异常] 执行 {methodName} 失败:{ex.InnerException?.Message ?? ex.Message}");
            }

            // 5. 执行切面的“后置逻辑”
            logAttr?.ExecuteAfter(methodName, instance);
            perfAttr?.ExecuteAfter(methodName, instance);
        }
    }

    // ===================== 第三步:复用原有OOP代码,标记切面特性 =====================
    /// <summary>
    /// 交通工具基类(OOP封装)
    /// </summary>
    public class Vehicle
    {
        private string _brand;
        private int _speed;

        public string Brand
        {
            get => _brand;
            set
            {
                if (string.IsNullOrWhiteSpace(value))
                    throw new ArgumentException("品牌不能为空");
                _brand = value;
            }
        }

        public int Speed
        {
            get => _speed;
            set
            {
                if (value < 0)
                    throw new ArgumentOutOfRangeException("速度不能为负数");
                _speed = value;
            }
        }

        public Vehicle(string brand, int speed)
        {
            Brand = brand;
            Speed = speed;
        }

        // 标记AOP切面特性:日志 + 性能监控
        [Log, Performance]
        public virtual void Run()
        {
            // 模拟方法执行耗时
            System.Threading.Thread.Sleep(100);
            Console.WriteLine($"{Brand} 以 {Speed} km/h 行驶(通用交通工具)");
        }

        public void Stop()
        {
            Console.WriteLine($"{Brand} 已停止行驶");
            Speed = 0;
        }
    }

    /// <summary>
    /// 汽车子类(OOP继承+多态)
    /// </summary>
    public class Car : Vehicle
    {
        private int _fuel;

        public int Fuel
        {
            get => _fuel;
            set
            {
                if (value < 0 || value > 100)
                    throw new ArgumentOutOfRangeException("油量需在0-100之间");
                _fuel = value;
            }
        }

        public Car(string brand, int speed, int fuel) : base(brand, speed)
        {
            Fuel = fuel;
        }

        // 同样标记AOP切面特性
        [Log, Performance]
        public override void Run()
        {
            System.Threading.Thread.Sleep(150);
            Console.WriteLine($"{Brand} 汽车(油量{Fuel}%)以 {Speed} km/h 行驶,耗油中...");
        }
    }

    /// <summary>
    /// 测试代码
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Car bmw = new Car("宝马", 120, 80);
                // 通过AOP执行器调用Run方法(植入切面逻辑)
                AopExecutor.ExecuteMethod(bmw, "Run");

                Console.WriteLine("-----");

                Vehicle baseVehicle = new Vehicle("通用交通工具", 80);
                AopExecutor.ExecuteMethod(baseVehicle, "Run");
            }
            catch (Exception ex)
            {
                Console.WriteLine("错误:" + ex.Message);
            }
        }
    }
}
2. 代码关键解释
(1)AOP 核心实现(切面特性 + 执行器)
  • 切面特性(Attribute)LogAttributePerformanceAttribute 是自定义特性,封装了 “日志记录”“性能监控” 的横切逻辑,标记在需要增强的方法上(如 Run());
  • AOP 执行器(AopExecutor):通过反射获取方法上的切面特性,在执行核心方法(Run())的前 / 后自动执行切面逻辑,实现 “无侵入式” 增强。
(2)OOP + AOP 结合

原有 OOP 代码(封装、继承、多态)完全无需修改,只需给 Run() 方法标记 [Log, Performance] 特性,就能自动获得日志和性能监控能力,这正是 AOP 的核心价值 ——横切逻辑与核心业务解耦

3. 运行结果

plaintext

[日志] 2026/1/22 15:00:00 - 开始执行 Car.Run 方法
宝马 汽车(油量80%)以 120 km/h 行驶,耗油中...
[日志] 2026/1/22 15:00:00 - 完成执行 Car.Run 方法
[性能] Car.Run 执行耗时:152 ms
-----
[日志] 2026/1/22 15:00:00 - 开始执行 Vehicle.Run 方法
通用交通工具 以 80 km/h 行驶(通用交通工具)
[日志] 2026/1/22 15:00:00 - 完成执行 Vehicle.Run 方法
[性能] Vehicle.Run 执行耗时:101 ms

三、工业级 AOP 实现(补充)

上面的 “特性 + 反射” 是入门级实现,实际项目中更常用 动态代理 框架(如 Autofac.DynamicProxy、Castle DynamicProxy),优势是:

  1. 无需手动写反射执行器,通过接口 / 虚方法自动生成代理类;
  2. 支持更复杂的切面逻辑(如异常拦截、事务管理);
  3. 性能比纯反射更高。

示例(Autofac.DynamicProxy 简化版):

csharp

运行

// 1. 安装NuGet包:Autofac、Autofac.DynamicProxy
// 2. 定义拦截器(切面逻辑)
public class LogInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        // 前置逻辑
        Console.WriteLine($"[日志] 开始执行 {invocation.Method.Name}");
        // 执行核心方法
        invocation.Proceed();
        // 后置逻辑
        Console.WriteLine($"[日志] 完成执行 {invocation.Method.Name}");
    }
}

// 3. 注册并使用代理
var builder = new ContainerBuilder();
builder.RegisterType<Car>().As<Vehicle>().EnableInterfaceInterceptors();
builder.RegisterType<LogInterceptor>();
using var container = builder.Build();

var car = container.Resolve<Vehicle>();
car.Run(); // 自动触发拦截器(AOP)

AOP vs AOP总结

  1. OOP vs AOP:OOP 按 “对象 / 业务” 划分代码(如汽车、电动车),AOP 按 “横切逻辑” 划分代码(如日志、性能),是对 OOP 的补充;
  2. C# 实现 AOP:入门级用 “自定义特性 + 反射”,工业级用动态代理框架(Autofac.DynamicProxy/PostSharp);
  3. 核心价值:AOP 让通用横切逻辑(日志、监控、事务)与核心业务解耦,无需重复编写,降低代码冗余。

泛型约束(Generic Constraints)

C# 中方法名称后面跟着 where 关键字的用法,这其实是泛型约束(Generic Constraints) 的核心语法,用来限制泛型类型参数的范围。

一、核心概念解释

在 C# 中,where 关键字专门用于泛型(方法、类、接口)中,作用是给泛型类型参数 T 设定规则,避免我们随意传入不符合要求的类型,同时也能让编译器识别出 T 可以调用的方法 / 属性。

简单来说:没有约束的泛型 T 只能调用 object 基类的方法(如 ToString());加了 where 约束后,T 就可以调用约束类型的所有成员。

二、常见用法示例

下面通过具体代码展示不同场景下 where 的用法:

1. 基础用法:约束泛型方法的类型参数
using System;

public class GenericMethodDemo
{
    // 泛型方法:T 必须是实现了 IComparable 接口的类型(才能调用 CompareTo 方法)
    public static T Max<T>(T a, T b) where T : IComparable<T>
    {
        // 因为有 where 约束,编译器知道 T 有 CompareTo 方法
        return a.CompareTo(b) > 0 ? a : b;
    }

    public static void Main()
    {
        // 合法:int 实现了 IComparable<int>
        int intMax = Max(10, 20);
        Console.WriteLine($"整数最大值:{intMax}"); // 输出:20

        // 合法:string 实现了 IComparable<string>
        string strMax = Max("apple", "banana");
        Console.WriteLine($"字符串最大值:{strMax}"); // 输出:banana

        // 非法(编译报错):自定义类未实现 IComparable,不符合 where 约束
        // MyClass obj1 = new MyClass();
        // MyClass obj2 = new MyClass();
        // Max(obj1, obj2);
    }
}

// 自定义测试类(未实现 IComparable)
public class MyClass { }
2. 多种常见约束类型

where 支持多种约束,满足不同场景需求:

using System;

public class ConstraintTypesDemo
{
    // 约束1:T 必须是引用类型(class)
    public static void RefTypeMethod<T>(T obj) where T : class
    {
        // 可以安全地将 T 赋值为 null(引用类型特性)
        T nullObj = null;
    }

    // 约束2:T 必须是值类型(struct)
    public static void ValueTypeMethod<T>(T obj) where T : struct
    {
        // T 不能为 null(值类型特性,可空值类型除外)
    }

    // 约束3:T 必须有无参构造函数(new())
    public static T CreateInstance<T>() where T : new()
    {
        // 可以直接 new T(),因为约束保证了无参构造存在
        return new T();
    }

    // 约束4:组合约束(T 是引用类型 + 实现 IDisposable)
    public static void DisposableMethod<T>(T obj) where T : class, IDisposable
    {
        obj.Dispose(); // 合法,因为 T 实现了 IDisposable
    }
}
3. 泛型类中的 where 用法(扩展)

除了方法,类的泛型参数也可以用 where

// 泛型类:T 必须继承自 Animal 类
public class AnimalShelter<T> where T : Animal
{
    public void Adopt(T animal)
    {
        animal.MakeSound(); // 合法,因为 T 是 Animal 的子类
    }
}

public class Animal
{
    public virtual void MakeSound()
    {
        Console.WriteLine("动物发出声音");
    }
}

public class Dog : Animal
{
    public override void MakeSound()
    {
        Console.WriteLine("汪汪汪");
    }
}

三、关键约束类型汇总

约束语法 作用
where T : class T 必须是引用类型(如 string、自定义类)
where T : struct T 必须是值类型(如 int、DateTime)
where T : new() T 必须有公共无参构造函数
where T : 基类名 T 必须是该基类的子类 / 本身
where T : 接口名 T 必须实现该接口
where T : U T 必须是 U 的子类 / 本身(泛型参数约束)

泛型约束总结

  1. where 是 C# 泛型的核心约束关键字,用于限制泛型类型参数的范围,避免类型滥用;
  2. 加了 where 约束后,编译器能识别泛型 T 的成员,允许调用约束类型的方法 / 属性;
  3. 常见约束包括 class/struct/new()/ 基类 / 接口,可组合使用(注意 new() 必须放在最后)。

通过 where 约束,你可以写出更安全、更灵活的泛型代码,既保留泛型的通用性,又避免无意义的类型传入。

C# 中如何给泛型接口使用 where 关键字来约束泛型类型参数

在 C# 中如何给泛型接口使用 where 关键字来约束泛型类型参数,这和泛型方法 / 类的 where 用法核心逻辑一致,只是作用对象变成了接口的泛型参数。

一、核心用法:泛型接口 + where 约束

泛型接口的 where 约束写在接口名称和泛型参数之后,语法和泛型类 / 方法完全兼容,目的是限制实现该接口的类必须使用符合约束的类型参数。

1. 基础示例:接口约束泛型参数实现指定接口
using System;

// 泛型接口:约束 T 必须实现 IComparable<T> 接口
public interface ISorter<T> where T : IComparable<T>
{
    // 因为有 where 约束,方法内可以安全调用 T 的 CompareTo 方法
    T[] Sort(T[] array);
}

// 实现接口:int 符合约束(实现了 IComparable<int>),所以合法
public class IntSorter : ISorter<int>
{
    public int[] Sort(int[] array)
    {
        Array.Sort(array);
        return array;
    }
}

// 测试代码
public class Test
{
    public static void Main()
    {
        var sorter = new IntSorter();
        int[] nums = { 3, 1, 2 };
        int[] sortedNums = sorter.Sort(nums);
        Console.WriteLine(string.Join(", ", sortedNums)); // 输出:1, 2, 3
    }
}
2. 多约束示例:接口约束泛型参数为引用类型 + 实现接口
// 泛型接口:T 必须是引用类型 + 实现 IDisposable 接口
public interface IResourceManager<T> where T : class, IDisposable
{
    // 管理资源:创建 → 使用 → 释放
    void ManageResource(T resource);
}

// 实现接口:FileStream 是引用类型 + 实现 IDisposable,符合约束
public class FileManager : IResourceManager<FileStream>
{
    public void ManageResource(FileStream resource)
    {
        // 使用资源
        byte[] buffer = new byte[1024];
        resource.Read(buffer, 0, buffer.Length);
        
        // 释放资源(因为 T 实现了 IDisposable)
        resource.Dispose();
    }
}
3. 接口约束泛型参数为值类型 / 有参构造
// 泛型接口:T 必须是值类型
public interface ICalculator<T> where T : struct
{
    T Add(T a, T b);
}

// 实现接口:double 是值类型,符合约束
public class DoubleCalculator : ICalculator<double>
{
    public double Add(double a, double b)
    {
        return a + b;
    }
}

// 泛型接口:T 必须有无参构造函数
public interface IFactory<T> where T : new()
{
    // 创建 T 的实例(因为 new() 约束,可直接 new T())
    T CreateInstance();
}

// 实现接口:Person 有无参构造,符合约束
public class PersonFactory : IFactory<Person>
{
    public Person CreateInstance()
    {
        return new Person();
    }
}

public class Person
{
    // 无参构造函数(满足 new() 约束)
    public Person() { }
    public string Name { get; set; }
}
4. 接口继承中的 where 约束(进阶)

当泛型接口继承另一个泛型接口时,子接口可以继承 / 强化父接口的约束:

csharp

运行

// 父接口:约束 T 是引用类型
public interface IBaseInterface<T> where T : class
{
    void DoSomething(T obj);
}

// 子接口:继承父接口约束 + 新增 T 实现 ICloneable 的约束
public interface IChildInterface<T> : IBaseInterface<T> where T : class, ICloneable
{
    T Clone(T obj);
}

// 实现子接口:string 是引用类型 + 实现 ICloneable,符合约束
public class StringHandler : IChildInterface<string>
{
    public void DoSomething(string obj)
    {
        Console.WriteLine($"处理字符串:{obj}");
    }

    public string Clone(string obj)
    {
        return (string)obj.Clone(); // 合法,因为 T 实现了 ICloneable
    }
}

二、注意事项

  1. 约束的继承性:实现泛型接口的类,其指定的类型参数必须完全满足接口的 where 约束,否则编译报错;
  2. new () 约束位置:如果接口的 where 包含 new(),必须放在所有约束的最后(如 where T : class, IDisposable, new());
  3. 接口本身非泛型时:普通非泛型接口不能用 wherewhere 仅针对泛型接口的类型参数。

泛型接口总结

  1. 泛型接口的 where 语法和泛型类 / 方法一致,写在接口名称 + 泛型参数后,用于约束接口的类型参数范围;
  2. 实现泛型接口的类,其指定的类型必须满足接口的 where 约束,否则无法编译;
  3. 接口的 where 支持组合约束(如 class + 接口struct + new()),核心目的是保证接口内的代码能安全调用泛型参数的成员。

通过给泛型接口加 where 约束,你可以确保所有实现该接口的类都遵循统一的类型规则,避免传入不符合预期的类型,让接口的通用性和安全性兼得。

其他

七大原则,24种设计模式,aop多种实现方式

https://blog.csdn.net/cao919/article/details/119916738

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐