C# 简化通知接口(INotifyPropertyChanging, INotifyPropertyChanged)

博客探讨了如何通过创建一个通知抽象类来减少C#中实现INotifyPropertyChanging和INotifyPropertyChanged接口的复杂性。原本的实现方式导致大量冗余代码,而抽象类的引入将这些重复代码封装,使得子类在继承时能更简洁地处理属性变更通知。通过示例展示了如何使用VS的批量更改功能进行快速代码改造。

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

原来类继承通知接口的写法过于复杂

最基础的类:

//最原始的基础类
class Country
{
	public string Code { get; set; }
	public string Name { get; set; }
}

继承接口后的写法:

//继承通知接口后的写法
class Country : INotifyPropertyChanging, INotifyPropertyChanged
{
	public event PropertyChangingEventHandler PropertyChanging;
    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyChanged(string propertyName)
            => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

    private void NotifyChanging(string propertyName)
            => PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(propertyName));

	private string code;
	public string Code 
	{ 
		get => code; 
		set
		{
			NotifyChanging("Code");
			code = value;
			NotifyChanged("Code");
		}
	}
	private string name;
	public string Name
	{ 
		get => name; 
		set
		{
			NotifyChanging("Name");
			name = value;
			NotifyChanged("Name");
		}
	}
}

进行对比发现多了很多代码,而且还额外多了一个private的字段,这样调试也会重复显示相同的数据,改一个名字至少要修改6个地方。

这个问题可以写个抽象类进行解决

//通知抽象类
public abstract class NotifyingEntity : INotifyPropertyChanging, INotifyPropertyChanged
{
	//储存属性值的字典
	//new() 是C# 9.0 的语法糖
	private Dictionary<string, object> property = new();
	/// <summary>
    /// 设置值时触发通知事件
    /// </summary>
    /// <param name="value">需要设置的值</param>
    /// <param name="propertyName">CallerMemberName属性可以获取调用方的名称(不需要手动设置)</param>
	protected void SetValueWithNotify(object value, [CallerMemberName] string propertyName = "")
	{
		NotifyChanging(propertyName);
        if (property.ContainsKey(propertyName))
        {
        	property[propertyName] = value;
        }
        else
        {
        	property.Add(propertyName, value);
        }
        NotifyChanged(propertyName);
    }
	/// <summary>
    /// 获得对应的值
    /// </summary>
    /// <typeparam name="T">需要转换的类型</typeparam>
    /// <param name="propertyName">CallerMemberName属性可以获取调用方的名称(不需要手动设置)</param>
    protected T GetValue<T>([CallerMemberName] string propertyName = "")
    	=> property.ContainsKey(propertyName) ? (T)property[propertyName] : default;

	public event PropertyChangingEventHandler PropertyChanging;
	public event PropertyChangedEventHandler PropertyChanged;

	private void NotifyChanged(string propertyName)
		=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

	private void NotifyChanging(string propertyName)
		=> PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(propertyName));
}

继承抽象类以后的代码:

class Country : NotifyingEntity 
{
	public string Code { get => GetValue<string>(); set => SetValueWithNotify(value); }
	public string Name { get => GetValue<string>(); set => SetValueWithNotify(value); }
}

简化后基本和原来一致,只需要注意获取值时候需要指定对应的类型。
利用VS的批量更改功能可以轻易的将{ get; set; } 替换成 { get => GetValue<>(); set => SetValueWithNotify(value); }
然后修改一下对应的类型就行了,更高级一点可以用正则去替换。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值