简体   繁体   English

遍历 lambda 表达式的属性?

[英]Iterate through the properties of a lambda expression?

How can I iterate through an expression and change the property names based on a custom attribute that I decorated them with?如何遍历表达式并根据我装饰它们的自定义属性更改属性名称?

I use the following code to get the custom attribute of a property, but it works for a simple expression with one property:我使用以下代码获取属性的自定义属性,但它适用于具有一个属性的简单表达式:

var comparison = predicate.Body as BinaryExpression;

var member = (comparison.Left.NodeType == ExpressionType.Convert ?
            ((UnaryExpression)comparison.Left).Operand :
            comparison.Left) as MemberExpression;

var value = comparison.Right as ConstantExpression;

var attribute = Attribute.GetCustomAttribute(member.Member, typeof(MyAttribute)) as MyAttribute;
var columnName = attribute.Name ?? member.Member.Name;
var columnValue = value.Value;

EDIT编辑

Deriving from ExpressionVisitor , I can change the property name by overriding the method VisitMember .ExpressionVisitor派生,我可以通过覆盖方法VisitMember来更改属性名称。

Is this the only place where a property name is used to build the expression?这是唯一一个使用属性名称来构建表达式的地方吗?

You can implement a System.Linq.Expressions.ExpressionVisitor to rewrite MemberExpression with the new mapped property.您可以实现System.Linq.Expressions.ExpressionVisitor以使用新的映射属性重写MemberExpression And yes VisitMember is the only place you have to implement this remapping, this is one of the advantages to expression trees and visitors.是的, VisitMember是您必须实施此重新映射的唯一地方,这是表达树和访问者的优势之一。 The only weird case you have to deal with is if the property's type is different to the type of the mapped property.您必须处理的唯一奇怪的情况是属性的类型是否与映射属性的类型不同。

void Main()
{
    var data = new List<TestClass>();
    data.Add(new TestClass()
    {
        FirstName = "First",
        LastName = "Last",
    });

    var q = data.AsQueryable().Select(x => x.FirstName);
    var vistor = new MyRewriter();

    var newExpression = vistor.Visit(q.Expression);
    var output = newExpression.ToString();
    //System.Collections.Generic.List`1[UserQuery+TestClass].Select(x => x.LastName)
}

class TestClass
{
    [MyAttribute(nameof(LastName))]
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

class MyAttribute : Attribute
{
    public string MapTo { get; }
    public MyAttribute(string mapTo)
    {
        MapTo = mapTo;
    }
}


class MyRewriter : ExpressionVisitor
{
    protected override Expression VisitMember(System.Linq.Expressions.MemberExpression node)
    {
        var att = node.Member.GetCustomAttribute<MyAttribute>();
        if (att != null)
        {
            var newMember = node.Expression.Type.GetProperty(att.MapTo);
            if (newMember != null)
            {
                return Expression.Property(
                    Visit(node.Expression), // Its very important to remember to visit the inner expression
                    newMember);
            }
        }

        return base.VisitMember(node);
    }
}

You can run this in LinqPad to test it.你可以在 LinqPad 中运行它来测试它。 This code assumes that you are mapping to a property.此代码假定您要映射到属性。

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

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