如何定义可接收赋值语句为参数的函数?代码重构场景
解决思路:用表达式树实现兼具赋值与添加Field的扩展方法
首先得明确:你想要的AllFields.Add(SomeProperty = new IntField(){...})写法直接用会有编译问题——因为SomeProperty是int类型,赋值表达式的结果是int(左操作数的类型),而你的AllFields是IList<IField>,没法把int实例加到列表里。我们可以用表达式树绕开这个限制,同时保留接近你想要的简洁语法。
步骤1:完善Field类与接口
先确保你的IntField、DecimalField实现了IField,并且支持隐式转换到对应的数值类型(这样赋值给int/decimal属性时不用显式强转):
public interface IField { string ColumnName { get; set; } string DisplayName { get; set; } bool IsEditable { get; set; } bool IsRequired { get; set; } } public class IntField : IField { public string ColumnName { get; set; } public string DisplayName { get; set; } public bool IsEditable { get; set; } public bool IsRequired { get; set; } public int Value { get; set; } // 隐式转换为int,让赋值语句能正常编译 public static implicit operator int(IntField field) => field.Value; } public class DecimalField : IField { public string ColumnName { get; set; } public string DisplayName { get; set; } public bool IsEditable { get; set; } public bool IsRequired { get; set; } public decimal Value { get; set; } // 隐式转换为decimal public static implicit operator decimal(DecimalField field) => field.Value; }
步骤2:编写扩展方法
我们用泛型表达式树作为参数,解析赋值语句,既执行属性赋值,又把Field对象加到列表:
public static class Extensions { public static void Add<TField>(this IList<IField> source, Expression<Func<TField>> assignmentExpression) where TField : IField { // 检查表达式是否是赋值操作 if (assignmentExpression.Body is not AssignmentExpression assignment) { throw new ArgumentException("参数必须是属性/字段的赋值表达式", nameof(assignmentExpression)); } // 编译并执行赋值,给目标属性赋值 var assignFunc = assignmentExpression.Compile(); var fieldInstance = assignFunc(); // 将Field对象添加到列表 source.Add(fieldInstance); } }
步骤3:调用方式
只需要用() =>把赋值语句包裹起来,就能同时完成属性赋值和Field添加:
IList<IField> AllFields = new List<IField>(); int SomeProperty; decimal SomeProperty2; // 给int属性赋值,同时把IntField加到列表 AllFields.Add(() => SomeProperty = new IntField { ColumnName = "SomeProperty", DisplayName = "Some Property", IsEditable = false, IsRequired = true, Value = 100 // 设置Field的数值 }); // 给decimal属性赋值,同时把DecimalField加到列表 AllFields.Add(() => SomeProperty2 = new DecimalField { ColumnName = "SomeProperty2", DisplayName = "Some Property 2", IsEditable = true, IsRequired = false, Value = 99.99m });
为什么这个方案可行?
表达式树让我们能获取到赋值语句右边的Field对象实例(即使左边是数值类型),同时编译执行表达式完成属性赋值。虽然比你最初设想的写法多了() =>包裹,但已经是最接近你需求的简洁实现了。
内容的提问来源于stack exchange,提问作者Eminem
相关产品推荐
相关产品推荐

