如何使用Func委托为类的DateTime字段赋值?
能否用Func委托实现通用的DateTime字段赋值?
你的原方案直接使用Func<SupportTicket, DateTime>无法实现赋值,原因很简单:Func是用于读取值的委托,它的签名决定了只能从对象中返回指定成员的值,没有修改对象成员的能力。
为什么原方案不可行?
Func<TSource, TResult>的本质是“输入一个TSource对象,返回一个TResult值”的委托,比如c => c.DateTimeField1这段Lambda,实际执行时只会返回DateTimeField1的当前值,完全不涉及写入操作。要完成赋值,你需要能执行写入逻辑的委托类型或其他手段。
可行的实现方案
这里提供两种符合需求的实现方式:
方案1:改用Action委托(简单直接)
Action委托用于执行无返回值的操作,我们可以定义一个接收对象和目标值的Action<MyClass, DateTime>,直接在委托中完成赋值:
private void SetDateTimeField(MyClass @class, Action<MyClass, DateTime> setter, DateTime date) { setter(@class, date); }
调用方式(明确写出赋值逻辑):
SetDateTimeField(@class, (c, d) => c.DateTimeField1 = d, DateTime.UtcNow); SetDateTimeField(@class, (c, d) => c.DateTimeField2 = d, DateTime.UtcNow);
方案2:用表达式树解析成员(保留原调用风格)
如果你想保留c => c.DateTimeField1这种简洁的调用方式,可以通过表达式树解析成员访问Lambda,动态生成赋值委托:
private void SetDateTimeField(MyClass @class, Expression<Func<MyClass, DateTime>> selector, DateTime date) { // 检查表达式是否为合法的成员访问 if (selector.Body is not MemberExpression memberExpr) { throw new ArgumentException("Selector必须是成员访问表达式", nameof(selector)); } // 构建赋值表达式,并编译为可执行的委托 var assignExpression = Expression.Assign(memberExpr, Expression.Constant(date)); var setter = Expression.Lambda<Action<MyClass>>(assignExpression, selector.Parameters).Compile(); // 执行赋值 setter(@class); }
调用方式和你最初的写法完全一致:
SetDateTimeField(@class, c => c.DateTimeField1, DateTime.UtcNow); SetDateTimeField(@class, c => c.DateTimeField2, DateTime.UtcNow);
总结
- 原
Func委托方案无法直接实现赋值,因为Func只有读取能力; - 优先选择
Action委托方案,代码更简洁高效; - 若要保留原调用风格,可通过表达式树实现,但会有轻微的性能开销(编译表达式的过程)。
内容的提问来源于stack exchange,提问作者Irmantas Želionis
相关产品推荐
相关产品推荐

