如何基于两个模型创建动态lambda表达式



我有两个类。

public class First
{
public int P {get; set;}
public int A {get; set;}
public int B {get; set;}
}
public class Second
{
public int P {get; set;}
public int C {get; set;}
}

我想计算这样的东西。

var first = A collection of First,
var second = A collection of Second
first.Select(f=> f.A * second.FirstOrDefault(s => s.P == f.P).C).Sum();

我可以更改f=>f.使用((的表达式中的A

ParameterExpression f =  Expression.Parameter(typeof(First), 'f');
Expression a = Expression.Property(f, "A");
var lambda = Expression.Lambda(Func<First, decimal>(a, f));
lambda.Complie()

我尝试更改s=>s.P==f.P在使用//内部λ的表达式中

ParameterExpression f =  Expression.Parameter(typeof(First), 'f');
ParameterExpression s =  Expression.Parameter(typeof(Second), 's');
Expression fp = Expression.Property(f, "P");
Expression sp = Expression.Property(s, "P");
Expression finalExp = Expression.Equal(sp, fp);
var lambda = Expression.Lambda(Func<Second, bool>(finalExp , s));
lambda.Complie()

我在这个代码中遇到了两个问题。

  1. 内部lambda代码在lambda处失败。Complie((。错误:从作用域"引用了类型为"First"的系统linq表达式变量"f",但未定义该变量
  2. 首先。选择(f=>f.A*second.FirstOrDefault(s=>s.P==f.P(.C(,f=<f.A是一个表达式,另一部分是小数,所以不能相乘

假设您需要处理此类表达式的通用方法:

public static int CalcSum<TFirst, TSecond>(IEnumerable<TFirst> first, IEnumerable<TSecond> second)
{
var f = Expression.Parameter(typeof(TFirst), "f");
var s = Expression.Parameter(typeof(TSecond), "s"); 
var firstQueryable = first.AsQueryable();
var secondQueryable = second.AsQueryable();
// s => f.P == s.P
var firstOrDefaultFilter = Expression.Lambda(
Expression.Equal(Expression.Property(f, "P"), Expression.Property(s, "P")),
s);
// second.FirstOrDefault(f.P == s.P)
var firstOrDefault = Expression.Call(typeof(Queryable), nameof(Queryable.FirstOrDefault),
new[] { typeof(TSecond) }, secondQueryable.Expression, firstOrDefaultFilter);
// second.FirstOrDefault(f.P == s.P).C
var propertyToSum = Expression.Property(firstOrDefault, "C");
// f => f.A * second.FirstOrDefault(f.P == s.P).C
var selectLambda = Expression.Lambda(
Expression.Multiply(Expression.Property(f, "A"), propertyToSum),
f);
// first.Select(f => f.A * second.FirstOrDefault(f.P == s.P).C)
var queryExpr = Expression.Call(typeof(Queryable), nameof(Queryable.Select),
new Type[] { typeof(TFirst), typeof(int) }, firstQueryable.Expression, selectLambda);
var query = firstQueryable.Provider.CreateQuery<int>(queryExpr);
return query.Sum();
}

最新更新