代码之家  ›  专栏  ›  技术社区  ›  Ondrej Petrzilka

将2参数Lambda表达式转换为1参数Lambda表达式(指定一个参数)

  •  4
  • Ondrej Petrzilka  · 技术社区  · 14 年前

    我有表情

    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 回复  |  直到 13 年前
        1
  •  3
  •   desco    14 年前

    可以重用源表达式体的修改版本

    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
    }
    
        2
  •  3
  •   Ghost4Man Stefan Agartsson    6 年前

    这很管用

    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

    是否有系统等效功能?