能否为C#属性的Getter和Setter设置默认函数?
在C#中为属性批量实现带IsDirty逻辑的Setter
C#本身不支持直接给类设置全局默认的Getter/Setter逻辑,但可以通过以下几种方案避免重复编写判断值变化、更新IsDirty的代码:
1. 基类封装通用Setter方法
创建一个包含通用设置逻辑的基类,子类的属性Setter直接调用基类方法即可:
public class DirtyTrackingBase { public bool IsDirty { get; private set; } protected bool SetProperty<T>(ref T backingField, T value) { if (!EqualityComparer<T>.Default.Equals(backingField, value)) { backingField = value; IsDirty = true; return true; } return false; } }
子类使用示例:
public class MyClass : DirtyTrackingBase { private string _property1; public string Property1 { get => _property1; set => SetProperty(ref _property1, value); } private int _property2; public int Property2 { get => _property2; set => SetProperty(ref _property2, value); } // 其余近100个属性都可以照此格式编写 }
2. T4模板批量生成代码
如果属性数量极多,可以用T4模板自动生成所有属性的完整代码,无需手动重复编写Setter逻辑:
创建一个名为MyClassGenerator.tt的文件,内容如下:
<#@ template language="C#" #> <#@ output extension=".cs" #> using System.Collections.Generic; public class MyClass { public bool IsDirty { get; private set; } = false; <# // 这里列出所有属性的类型和名称 var properties = new[] { new { Type = "string", Name = "Property1" }, new { Type = "string", Name = "Property2" }, new { Type = "int", Name = "Property3" }, // 继续添加剩余属性... }; foreach (var prop in properties) { var backingField = "_" + prop.Name.ToLowerInvariant(); #> private <#= prop.Type #> <#= backingField #>; public <#= prop.Type #> <#= prop.Name #> { get => <#= backingField #>; set { if (!EqualityComparer<<#= prop.Type #>>.Default.Equals(<#= backingField #>, value)) { <#= backingField #> = value; IsDirty = true; } } } <# } #> }
保存后,Visual Studio会自动生成对应的.cs文件,包含所有属性的完整实现。
3. 编译时源生成器(C# 9+)
对于追求编译时性能的场景,可以使用C#源生成器,通过自定义特性标记需要跟踪的属性,自动生成Setter逻辑:
首先定义特性:
[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)] public sealed class TrackDirtyAttribute : Attribute { }
然后编写源生成器(需创建单独的类库项目),监听带有[TrackDirty]的属性,自动生成包含IsDirty更新逻辑的Setter代码。这种方式无需运行时反射,性能最优。
内容的提问来源于stack exchange,提问作者MrBott_a
相关产品推荐
相关产品推荐

