需要帮助将lambda转换为表达式树

时间:2017-09-17 02:19:45

标签: c# linq lambda tree expression

我已经玩了好几个小时,可以使用一双新鲜的眼睛。好的,有关表达树的经验比我更多的人。男人的曲线很陡!

考虑以下内容。 (这有效,但我需要将帐户作为字符串传递。帐户是帐户列表)

repo = repo.Where(x => x.Accounts.FirstOrDefault().Id == AccountId);

这是我到目前为止所做的。

            var parameterExp = Expression.Parameter(typeof(Boat), "x");
            var propertyExp = Expression.Property(parameterExp, "Accounts");

            MethodInfo method1 = typeof(Queryable).GetMethods(BindingFlags.Public | BindingFlags.Static).First(m => m.Name == "FirstOrDefault");

            // This gives me a Queryable of Account FirstOrDefault
            var specificMethod = method1.MakeGenericMethod(propertyExp.Type);

            // right here is where I am getting stuck
            var firstOrDefaultAccountExpression = // I need to get an Account so I can query against the Id ??


            MethodInfo method = typeof(long).GetMethod("Equals", new[] { typeof(long) });
            var someValue = Expression.Constant(AccountId, typeof(long));
            var containsMethodExp = Expression.Call(firstOrDefaultAccountExpression , method, someValue);

            Expression<Func<Boat, bool>> predicate = Expression.Lambda<Func<Boat, bool>>
                         (containsMethodExp, parameterExp);


            repo = repo.Where(predicate);

我能够将此代码用于常规字符串成员。我似乎无法弄清楚清单。最终我试图找回一个BoatId = long

的船只清单

提前致谢!

1 个答案:

答案 0 :(得分:1)

var parameterExp = Expression.Parameter(typeof(Boat), "x");
Expression propertyExp = Expression.Property(parameterExp, "Accounts");

Type elementType = propertyExp.Type.GetGenericArguments()[0];

MethodInfo method1 = typeof(Enumerable).GetMethods(BindingFlags.Public | BindingFlags.Static).First(m => m.Name == "FirstOrDefault");

// This gives me a Queryable of Account FirstOrDefault
var specificMethod = method1.MakeGenericMethod(elementType);

//propertyExp = Expression.TypeAs(propertyExp, typeof(IEnumerable<>).MakeGenericType(elementType));

var firstOrDefaultAccountExpression = Expression.Call(specificMethod, propertyExp);

var idExpr = Expression.PropertyOrField(firstOrDefaultAccountExpression, "Id");

MethodInfo method = typeof(long).GetMethod("Equals", new[] { typeof(long) });
var someValue = Expression.Constant(AccountId, typeof(long));
var containsMethodExp = Expression.Call(idExpr, method, someValue);

Expression<Func<Boat, bool>> predicate = Expression.Lambda<Func<Boat, bool>>
             (containsMethodExp, parameterExp);

repo = repo.Where(predicate);

List<>必须投放到IEnumerable<>才能调用FirstOrDefault我会发誓,如果没有演员阵容就行不通,但现在它工作,奇怪。所以我评论了这条线。但在两个版本中它都能够在linq2sql中生成sql代码,我测试了它。您不需要Queryable来访问Accounts属性(我不确定是否可以)。查看代码的第一行,即非表达式查询。即便如此,FirstOrDefault也是Enumerable的方法。它的目的是通过定义表达式来定义转换,而不是实际做任何事情的函数。