C#中能否自动生成可触发INotifyPropertyChanged事件的字段/属性Setter?
当然可以!你现在碰到的手动写重复Setter代码的问题,很多C#开发者都深有同感——毕竟每个属性都要写值判断、更新字段、触发事件的逻辑,真的挺繁琐的。结合你提到的SettingEntries类需要触发INotifyPropertyChanged来通知保存设置的场景,给你分享几种实用的自动实现方式:
1. 用基类+CallerMemberName简化重复代码
这是最基础的“半自动”方式,先写一个通用基类封装事件触发逻辑,利用CallerMemberName特性自动获取属性名,避免手动传入字符串:
using System.ComponentModel; using System.Runtime.CompilerServices; public class ObservableBase : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } // 你的SettingEntries类继承这个基类即可 public class SettingEntries : ObservableBase { private string _apiUrl; public string ApiUrl { get => _apiUrl; set { if (_apiUrl != value) { _apiUrl = value; OnPropertyChanged(); // 不需要手动传属性名啦! } } } private int _timeout; public int Timeout { get => _timeout; set { if (_timeout != value) { _timeout = value; OnPropertyChanged(); } } } }
这样每个属性的Setter只需要写值判断和调用OnPropertyChanged(),重复代码少了很多。
2. T4模板自动生成属性代码
如果你的属性特别多,还可以用T4模板自动生成完整的属性和Setter逻辑。只需要在模板里定义好字段列表,模板会帮你自动生成包含事件触发的属性代码:
先创建一个.tt文件,写入类似逻辑:
<#@ template language="C#" #> <#@ output extension=".cs" #> using System.ComponentModel; using System.Runtime.CompilerServices; public class SettingEntries : ObservableBase { <# // 在这里定义你的字段和类型 var properties = new Dictionary<string, string> { {"ApiUrl", "string"}, {"Timeout", "int"}, {"MaxRetries", "int"} }; foreach (var prop in properties) { var fieldName = "_" + prop.Key.ToLower(); #> private <#= prop.Value #> <#= fieldName #>; public <#= prop.Value #> <#= prop.Key #> { get => <#= fieldName #>; set { if (<#= fieldName #> != value) { <#= fieldName #> = value; OnPropertyChanged(); } } } <# } #> }
保存后,Visual Studio会自动生成对应的.cs文件,后续添加新字段只需要修改模板里的字典就行,完全不用手动写属性。
3. 用Fody.PropertyChanged实现完全自动
如果你想彻底摆脱手动写Setter的麻烦,可以试试Fody.PropertyChanged这个库——它通过IL织入(IL Weaving)技术,在编译时自动给你的属性添加INotifyPropertyChanged的触发逻辑,你只需要给类加个特性就行:
- 先通过NuGet安装
PropertyChanged.Fody包 - 给你的
SettingEntries类添加特性:
using PropertyChanged; [AddINotifyPropertyChangedInterface] public class SettingEntries { // 只需要定义自动属性,Fody会自动帮你添加触发逻辑! public string ApiUrl { get; set; } public int Timeout { get; set; } public int MaxRetries { get; set; } }
编译后,这个类会自动实现INotifyPropertyChanged接口,每个属性的Setter都会自动判断值变化并触发事件,完全不用写任何额外的代码,非常适合你的场景。
这些方法都能帮你自动生成触发INotifyPropertyChanged的Setter,让你的SettingEntries类维护起来更轻松,不用再为每个属性写重复的逻辑啦!
备注:内容来源于stack exchange,提问作者Alaric de Ruiter

