c# - 迭代 lambda 表达式的属性?

标签 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 来更改属性名称。

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

最佳答案

您可以实现 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 中运行它来测试它。此代码假定您要映射到属性。

关于c# - 迭代 lambda 表达式的属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36716464/

相关文章:

c# - 如何从网页中的链接读取 url 参数的内容?

c# - 涉及锁时,代码契约(Contract)警告 "ensures unproven"

c# - 如何使用 Linq-To-Sql 在同一查询中进行 TOP、ORDER BY 和 DISTINCT?

c# - 我怎样才能从几个表达式的并集组成一个表达式树?

c# - 表达式树参数是否需要重用相同的实例?

c# - 有没有办法在 Unity 的控制台中使用超链接?

c# - CaSTLy Dynamic Proxy - 获取目标方法的返回值

entity-framework - 如何改进这个 Entity Framework Core 查询?

c# - linq 的优化或替代(用于聚合)C#

c# - 如何从两个表达式创建表达式 AND 子句