Преобразование лямбда-выражения с двумя аргументами в лямбда-выражение с одним аргументом (указание одного аргумента) - PullRequest
4 голосов
/ 20 августа 2010

У меня есть выражение

Expression<Func<Car, Driver, bool>> CanBeDrivenBy = 
    (car, driver) => car.Category == 'B' && driver.Age > 18;

и я хочу получить машины, которыми может управлять какой-то водитель

IQueryable<Cars> cars = ...;
Driver driver = ...;
cars.Where(CanBeDrivenBy);   // Fail, expecting Expression<Func<Car, bool>>

Так что мне нужно конвертировать Expression<Func<Car, Driver, bool>> в Expression<Func<Car, bool>> (указать драйвер)

Да, я могу использовать

cars.Where(c => c.Category == 'B' && driver.Age > 18);

но мне нужно решение с выражением, которое можно динамически изменять. И мне нужно передать выражение (с использованием структуры лица)

Ответы [ 2 ]

3 голосов
/ 20 августа 2010

вы можете повторно использовать модифицированную версию тела выражений

using System;
using System.Linq.Expressions;

public class Program
{
    public static Expression<Func<T1, TResult>> Bind2nd<T1, T2, TResult>(Expression<Func<T1, T2, TResult>> source, T2 argument)
    {
        Expression arg2 = Expression.Constant(argument, typeof (T2));
        Expression newBody = new Rewriter(source.Parameters[1], arg2).Visit(source.Body);
        return Expression.Lambda<Func<T1, TResult>>(newBody, source.Parameters[0]);
    }

    public static void Main(string[] args)
    {
        Expression<Func<string, string, int>> f = (a, b) => a.Length + b.Length;
        Console.WriteLine(f); // (a, b) => (a.Length + b.Length)

        Console.WriteLine(Bind2nd(f, "1")); // a => (a.Length + "1".Length)
    }

    #region Nested type: Rewriter

    private class Rewriter : ExpressionVisitor
    {
        private readonly Expression candidate_;
        private readonly Expression replacement_;

        public Rewriter(Expression candidate, Expression replacement)
        {
            candidate_ = candidate;
            replacement_ = replacement;
        }

        public override Expression Visit(Expression node)
        {
            return node == candidate_ ? replacement_ : base.Visit(node);
        }
    }

    #endregion
}
3 голосов
/ 20 августа 2010

Это РАБОТАЕТ

Я написал эту функцию, чтобы уменьшить количество аргументов с 2 до 1, указав второй аргумент.

public static Expression<Func<T1, TResult>> Bind2nd<T1, T2, TResult>(Expression<Func<T1, T2, TResult>> source, T2 argument)
{
    Expression arg2 = Expression.Constant(argument, typeof(T2));
    var arg1 = Expression.Parameter(typeof(T1));
    return Expression.Lambda<Func<T1, TResult>>(Expression.Invoke(source, arg1, arg2), arg1);
}

Использование:

IQueryable<Car> cars = ...;
Driver driver = ...;
cars.Where(Bind2nd(CanBeDrivenBy, driver));

arg1 - это временное хранилище между вызовами.

Существует ли какая-либо системная эквивалентная функция?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...