从<t1,t2,bool>创建Linq表达式<t2,t1,bool>

时间:2018-08-15 21:03:16

标签: c# linq associations predicate linq-expressions

我想防止重复用于ORM中联接/关联双方的相同谓词逻辑。我应该:

1)使用Func<T1, T2, bool>并使用扩展方法来获取表达式:

public static Expression<Func<T1, T2, bool>> ExpressionFuncT1T2<T1, T2>(this Func<T1, T2, bool> func) => (t1, t2) => func(t1, t2);

public static Expression<Func<T2, T1, bool>> ExpressionFuncT2T1<T1, T2>(this Func<T1, T2, bool> func) => (t1, t2) => func(t2, t1);

2)使用Expression<Func<T1, T2, bool>>的一侧,并根据此stackoverflow question的答案将其转换为Expression<Func<T2, T1, bool>>,如下所示:

public static Expression<Func<T2, T1, bool>> WhatToCallThis<T1,T2>(
         this Expression<Func<T1, T2, bool>> predicate) {

      var t1 = Expression.Parameter(typeof(T1), "t1");
      var t2 = Expression.Parameter(typeof(T2), "t2");
      return Expression.Lambda<Func<T2, T1, bool>>(
          Expression.Invoke(predicate, 
          Expression.PropertyOrField(t2, "T1"), 
          Expression.PropertyOrField(t1, "T2")
          ), t2, t1);
    }

您还要给这个方法命名吗?

1 个答案:

答案 0 :(得分:0)

似乎下面所有的3种方法都可以使用,但是在性能上最好使用哪种方法?

SwapParameters1使用 Expression.Lambda

public static Expression<Func<T2, T1, TResult>> SwapParameters1<T1, T2, TResult>
  (this Expression<Func<T1, T2, TResult>> exprFunc)
  => Expression.Lambda<Func<T2, T1, TResult>>(exprFunc.Body
                                            , exprFunc.Parameters[1]
                                            , exprFunc.Parameters[0]);

SwapParameters2使用 .Compile():

public static Expression<Func<T2, T1, TResult>> SwapParameters2<T1, T2, TResult>
  (this Expression<Func<T1, T2, TResult>> exprFunc)
  => (t1, t2) => exprFunc.Compile()(t2, t1);

SwapParameters3使用 ExpressionVisitor 替换参数(此so问题帮助了):

public static Expression<Func<T2, T1, TResult>> SwapParameters3<T1, T2, TResult>
  (this Expression<Func<T1, T2, TResult>> exprFunc) {
  var param1 = Expression.Parameter(typeof(T1));
  var param2 = Expression.Parameter(typeof(T2));
  return Expression.Lambda<Func<T2, T1, TResult>>(exprFunc.Body
    .Replace(exprFunc.Parameters[0], param1)
    .Replace(exprFunc.Parameters[1], param2)
    , param1, param2);
}

public static Expression<Func<TNewParam, TResult>> ReplaceParameter<TNewParam, TOldParam, TResult>
  (this Expression<Func<TOldParam, TResult>> expression)
  where TNewParam : TOldParam {
  var param = Expression.Parameter(typeof(TNewParam));
  return Expression.Lambda<Func<TNewParam, TResult>>(
    expression.Body.Replace(expression.Parameters[0], param)
    , param);
}

public class ReplaceVisitor : ExpressionVisitor {
  private readonly Expression from, to;
  public ReplaceVisitor(Expression from, Expression to) {
    this.from = from;
    this.to = to;
  }

  public override Expression Visit(Expression node) => node == from ? to : base.Visit(node);
}

public static Expression Replace(this Expression expression, Expression searchExpression, Expression replaceExpression)
  => new ReplaceVisitor(searchExpression, replaceExpression).Visit(expression);

我倾向于使用SwapParameters1。