繁体   English   中英

如何构建属性选择器?

[英]How to build a properties selector?

我试图使用以下格式进行更新 function:

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

如何读取选择器中选择的属性? 我需要属性的名称。

这是因为我想让更新 function 更智能,所以它只更新必须更新的内容。 它适用于 sql,它是一个存储库 function。

谢谢。

更新澄清:

我希望能够像这样调用更新:

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

所以表达式的 IEnumerable 不是一个选项,但如果上面的内容更加困难,我会这样做......

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

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);

    // ...
}

尽管这很容易被滥用。

如果您不介意将更新代码编写为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...
}

注意,助手 function 是一个基本的助手,您可以使用更扩展的可重用助手 function 来获得名称,周围有很多

示例代码(第一个匿名 object 只是为了创建一个示例对象): Update(new { foo = "a", bar = 5}, x=>x.foo, x=>x.bar);

现在有趣的是,您可以通过删除新表达式来强制使用单个表达式,或者您可以组合 function,并且仍然允许匿名,方法是在帮助程序 function 中添加对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});

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM