迭代lambda表达式的属性?

时间:2016-04-19 11:02:05

标签: c# linq expression-trees

如何迭代表达式并根据我用它们修饰的自定义属性更改属性名称?

我使用以下代码来获取属性的自定义属性,但它适用于具有一个属性的简单表达式:

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;

修改

ExpressionVisitor派生,我可以通过覆盖方法VisitMember来更改属性名称。

这是唯一一个使用属性名来构建表达式的地方吗?

1 个答案:

答案 0 :(得分:2)

您可以使用新的映射属性实现System.Linq.Expressions.ExpressionVisitor重写MemberExpression。是的VisitMember是您实现此重新映射的唯一地方,这是表达树和访问者的优势之一。您必须处理的唯一奇怪的情况是属性的类型是否与映射属性的类型不同。

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

您可以在LinqPad中运行它来测试它。此代码假定您要映射到属性。