Moving an expression tree and extraction parameters

I am writing a kind of mapping tool. I have a method that looks like this (simplified):

   public void RegisterMapping<TTarget, TSource>(string propertyName, 
                                                 Expression<Func<TSource, object>> memberMap)

memberMapis an expression that defines how to convert a property from TSourceto TTarget. For business logic, I need to extract all property references from it TSource. For example, from

x => x.Customers.Where(c => c.Orders.Any())

I would like to receive Customersfrom

x => x.FirstName + " " + x.LastName

FirstNameand LastName(maybe like string [], PropertyInfotrivially convert to).

How should I do it? My first approach was to manually move the tree, checking the type of node and checking various properties depending on the type of node (for example, Operandfor unary expressions, Argumentsto call a function), to determine if any of these are a property TSource. Then I discovered a list of expression types , and I gave up - even if I support only the most common types, this is still a lot of work. Then I found ExpressionVisitor . It looks better, but there is still a lot of work to override visitor methods, and I would like to find out if there is another option, using perhaps a more specialized structure, before I devote my time to this.

+4
source share
1

, , ExpressionVisitor . Visit..., . , , -

public class MemberAccessVisitor : ExpressionVisitor
{
    private readonly Type declaringType;
    private IList<string> propertyNames = new List<string>();

    public MemberAccessVisitor(Type declaringType)
    {
        this.declaringType = declaringType;
    }

    public IEnumerable<string> PropertyNames { get { return propertyNames; } }

    public override Expression Visit(Expression expr)
    {
        if (expr != null && expr.NodeType == ExpressionType.MemberAccess)
        {
            var memberExpr = (MemberExpression)expr;
            if (memberExpr.Member.DeclaringType == declaringType)
            {
                propertyNames.Add(memberExpr.Member.Name);
            }
        }

        return base.Visit(expr);
    }
}

, , , PropertyInfo,

:

var visitor = new MemberAccessVisitor(typeof(TSource));

visitor.Visit(memberMap);

var propertyNames = visitor.PropertyNames;
+3

Source: https://habr.com/ru/post/1598688/


All Articles