Как создать ExpressionTree с несколькими вызовами методов - PullRequest
4 голосов
/ 20 марта 2012

В настоящее время у меня есть следующий код, который позволяет мне вызывать любой метод, необходимый для свойства EmailAddress моего объекта, и он прекрасно работает:

public static Expression<Func<T, bool>> BuildEmailAddressLambda(string method, params object[] args) {
    var e = Expression.Parameter(typeof(T), "e");
    var propertyInfo = typeof(T).GetProperty("EmailAddress");
    var m = Expression.MakeMemberAccess(e, propertyInfo);
    var mi = m.Type.GetMethod(method, args.Select(a => a.GetType()).ToArray());
    var c = args.Select(a => Expression.Constant(a, a.GetType())).ToArray();

    Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(Expression.Call(m, mi, c), e);
    return lambda;
}

// called:
lambda = LambdaExpressionHelper<MailingListMember>.BuildEmailAddressLambda("StartsWith", "r", StringComparison.OrdinalIgnoreCase);

Однако теперь мне нужно изменить код, чтобы он работал для членов моего объекта, отличных от EmailAddress. В частности, я хотел бы создать дерево для покрытия следующего выражения, где используются несколько вызовов методов:

e.GetStringValue(12).StartsWith("r", StringComparison.OrdinalIgnoreCase); 

Я сделал несколько попыток, каждая из которых заканчивается различными ошибками. Я чувствую, что упускаю что-то в логике создания ExpressionTrees, и некоторая помощь с этим будет принята с благодарностью.

Спасибо

1 Ответ

4 голосов
/ 20 марта 2012

Это хорошо для тебя?

public static Expression<Func<T, bool>> BuildEmailAddressLambda<T>(
    string member, IEnumerable<object> memberArgs, string method, params object[] args)
{
    var e = Expression.Parameter(typeof(T), "e");
    var memberInfo =
        (MemberInfo) typeof(T).GetField(member) ??
        (MemberInfo) typeof(T).GetProperty(member) ??
        (MemberInfo) typeof(T).GetMethod(member, (memberArgs ?? Enumerable.Empty<object>()).Select(p => p.GetType()).ToArray());
    Expression m;
    if (memberInfo.MemberType == MemberTypes.Method)
    {
        var a = memberArgs.Select(p => Expression.Constant(p));
        m = Expression.Call(e, (MethodInfo) memberInfo, a);
    }
    else
    {
        m = Expression.MakeMemberAccess(e, memberInfo);
    }
    var mi = m.Type.GetMethod(method, args.Select(a => a.GetType()).ToArray());
    var c = args.Select(a => Expression.Constant(a, a.GetType()));

    return Expression.Lambda<Func<T, bool>>(Expression.Call(m, mi, c), e);
}

// called:
lambda = LambdaExpressionHelper<MailingListMember>.BuildEmailAddressLambda("EmailAddress", null, "StartsWith", "r", StringComparison.OrdinalIgnoreCase);
// or
lambda = LambdaExpressionHelper<MailingListMember>.BuildEmailAddressLambda("GetStringValue", new object[] { 12 }, "StartsWith", "r", StringComparison.OrdinalIgnoreCase);
...