如何构建属性选择器?

3phpmpom  于 2021-08-09  发布在  Java
关注(0)|答案(2)|浏览(342)

我试图用以下格式创建更新函数:

public int Update(
        Item Item, 
        Expression<Func<Item, object>> selector)

如何读取选择器中选择的属性?我需要房产的名字。
这是因为我想使更新功能更智能,所以它只更新必须更新的内容。它用于sql,是一个存储库函数。
谢谢。
更新澄清:
我希望能够像这样调用update:

Update(item, x => new { x.Property1, x.Property2 })

所以ienumerable的表达式不是一个选项,但如果上面是一个更困难的我会这样做。。。

guz6ccqo

guz6ccqo1#

假设您不想验证表达式是否实际返回属性值,这将起作用:

public int Update(Item item, params Expression<Func<Item, object>>[] selectors)
{
    var propertyNames = selectors
        .Select(expression => ((MemberExpression)expression.Body).Member.Name);

    // ...
}

否则,你需要一些类似于这个综合答案的东西。
更新
如果要使用匿名对象,可以执行以下操作:

public int Update<TProps>(Item item, Expression<Func<Item, TProps>> selector)
{
    var propertyNames = typeof(TProps)
        .GetProperties()
        .Select(prop => prop.Name);

    // ...
}

尽管这很容易被滥用。

8fsztsew

8fsztsew2#

如果您不介意将更新代码编写为 Update(item, x => x.Property1, x=> x.Property2 ) ,它会像johnathans的回答一样可读,而且写起来更容易一些。
尽管如果您添加泛型,您可以强制x为同一类型,并将其用于不同的对象 Item ```
int Update(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...

}

注意,helper函数是一个基本的函数,您可以使用一个更扩展的可重用helper函数来获取名称,有很多这样的函数
示例代码(第一个匿名对象只是创建一个示例对象): `Update(new { foo = "a", bar = 5}, x=>x.foo, x=>x.bar);` 有趣的是,可以通过删除new来强制一个表达式,也可以通过添加对 `NewExpression` 在helper函数内部(当然,将其更改为允许多个名称):

int Update(T item, params Expression<Func<T, object>>[] selectors)
{
IEnumerable 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});

相关问题