You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在父类Parent中监听子类Child的属性变更并触发处理方法?

这个需求很实用——在父类里统一处理子类的属性变更,能省不少重复代码。下面给你几种可行的实现方式,你可以根据自己的场景来选:

方案一:用INotifyPropertyChanged(推荐,符合.NET规范)

这是.NET里处理属性变更的标准玩法,让父类实现这个接口,然后子类在属性setter里触发变更事件,父类监听事件就能调用MyHandler了。

先修改Parent类:

using System.ComponentModel;
using System.Runtime.CompilerServices;

public class Parent : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public Parent()
    {
        // 监听属性变更事件,触发时自动调用MyHandler
        PropertyChanged += (sender, args) => MyHandler(args);
    }

    // 提供给子类调用的触发方法,CallerMemberName能自动获取当前属性名
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public void MyHandler(PropertyChangedEventArgs args)
    {
        Console.WriteLine($"属性 {args.PropertyName} 已经更新");
        // 这里可以编写你的业务处理逻辑
    }
}

然后子类Child只需要在属性setter里调用父类的OnPropertyChanged就行:

public class Child : Parent
{
    private string _name;
    public string Name
    {
        get => _name;
        set
        {
            if (_name != value)
            {
                _name = value;
                // 触发属性变更事件,父类会自动监听到
                OnPropertyChanged();
            }
        }
    }
}

这种方式的好处是代码清晰、性能优异,完全符合.NET的设计习惯。你可以在父类的说明文档里明确告诉用户:继承这个类时,属性setter里记得调用OnPropertyChanged,甚至可以给个代码模板,用户照着写非常方便。

方案二:用动态代理(无需修改子类代码)

如果不想让用户写额外的setter逻辑,那可以用动态代理来拦截子类的属性赋值操作。这里需要用到Castle DynamicProxy第三方库,不过要注意性能和实例创建方式的变化。

首先安装Castle.Core NuGet包,然后修改Parent类:

using Castle.DynamicProxy;
using System.ComponentModel;

public class Parent : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        // 判断当前调用是不是属性的set方法
        if (invocation.Method.Name.StartsWith("set_"))
        {
            // 先执行原本的赋值操作
            invocation.Proceed();
            // 提取属性名(去掉方法名前的"set_"前缀)
            var propertyName = invocation.Method.Name.Substring(4);
            // 触发处理方法
            MyHandler(new PropertyChangedEventArgs(propertyName));
        }
        else
        {
            // 非set方法直接执行原逻辑
            invocation.Proceed();
        }
    }

    public void MyHandler(PropertyChangedEventArgs args)
    {
        Console.WriteLine($"属性 {args.PropertyName} 发生了变更");
    }
}

子类可以完全保持原样:

public class Child : Parent
{
    public string Name { get; set; }
}

但使用时需要通过代理创建实例,不能直接new:

var proxyGenerator = new ProxyGenerator();
Child child = proxyGenerator.CreateClassProxy<Child>();
child.Name = "小明"; // 此时会触发Parent类中的MyHandler

这种方式的优点是子类完全不用修改,用户使用起来省心;缺点是要引入第三方库,实例创建方式有变化,性能也比第一种方案稍差,适合对性能要求不高的场景。

总结

如果能让子类配合编写少量setter逻辑,方案一绝对是首选,规范又好用;如果完全不想改动子类代码,可以考虑方案二,但要权衡好性能和使用成本。

内容的提问来源于stack exchange,提问作者TamerM

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:53:33