如果您不介意将更新代码编写为 Update(item, x => x.Property1, x=> x.Property2 ),它会像 Johnathans 回答所示那样可读且更容易编写。
虽然如果你添加一个泛型,你可以强制 x 为同一类型,并将其重用于除Item之外的不同对象
int Update<T>(T item, params Expression<Func<T, object>>[] selectors)
{
string getName(Expression e)
{
if(e is LambdaExpression l)
return getName(l.Body);
if(e is MemberExpression m)
return m.Member.Name;
if(e is UnaryExpression u)
return getName( u.Operand);
throw new NotImplementedException();
}
var names = selectors.Select(getName);
//update code...
}
注意,辅助函数是一个基本的,你可以使用更扩展的可重用辅助函数来获取名称,周围很多
示例代码(第一个匿名对象只是为了创建一个示例对象):
Update(new { foo = "a", bar = 5}, x=>x.foo, x=>x.bar);
现在有趣的是,您可以通过删除 new 来强制使用单个表达式,或者您可以组合该函数,但仍然允许匿名,方法是在辅助函数中添加对 NewExpression 的检查(将其更改为当然允许多个名称):
int Update<T>(T item, params Expression<Func<T, object>>[] selectors)
{
IEnumerable<string> getName(Expression e)
{
if (e is LambdaExpression l)
return getName(l.Body);
if (e is MemberExpression m)
return new[] { m.Member.Name };
if (e is UnaryExpression u)
return getName(u.Operand);
if (e is NewExpression n) // <- to account for the anonymous object
return n.Arguments.SelectMany(getName);
throw new NotImplementedException();
}
var names = selectors.SelectMany(getName);
// etc
}
这样,您可以选择(甚至混合)。这两个调用产生相同的结果:
Update(new { foo = "a", bar = 5}, x=>x.foo, x=>x.bar);
Update(new { foo = "a", bar = 5 }, x => new { x.foo, x.bar});