无法将此 linq 转换为动态表达式树
Can't convert this linq to dynamic expression tree
我正在尝试创建一个表达式,该表达式将 FirstOrDefault 与 IEnumerable<TComparable>
表达式的谓词一起使用,但它给了我这个错误:
参数 'o' 未绑定到指定的 LINQ to Entities 查询表达式
我有一个这样的 linq 表达式:
IEnumerable<string> names = new List<string>() { "abc", "def", "ghi" };
string name = names.FirstOrDefault(o => o.Contains("abc"));
public static Expression FirstOrDefault(this Expression expression, Type collectionValuesType, MethodInfo comparerMethod, string keyword)
{
MethodInfo firstOrDefaultMethod = typeof(Enumerable).GetMethods()
.FirstOrDefault(o => o.Name == "FirstOrDefault" && o.GetParameters().Length == 2)
.MakeGenericMethod(new Type[] { collectionValuesType });
Type firstOrDefaultDelegateType = typeof(Func<,>).MakeGenericType(collectionValuesType, typeof(bool));
ParameterExpression firstOrDefaultPredicateParameter = Expression.Parameter(collectionValuesType);
//THIS LINE binds the "o" in (o => o.Contains("abc")) , and it is where I'm stuck with since yesterday!
MemberExpression firstOrDefaultParameterO = Expression.Property(expression, typeof(string).GetProperty(???));
//o => o.ComparerMethod(keyword)
MethodCallExpression firstOrDefaultCompareExpression = Expression.Call(
firstOrDefaultParameterO,
comparerMethod,
Expression.Constant(keyword, typeof(string))
);
//expression.FirstOrDefault(firstOrDefaultCompareExpression);
return Expression.Call(
firstOrDefaultMethod,
expression,
Expression.Lambda(firstOrDefaultDelegateType, firstOrDefaultCompareExpression, Expression.Parameter(collectionValuesType))
);
}
如果我有一个复杂的类型,我会这样使用:
public class Example { public string Name; }
//o => o.Name.Contains("abc"))
MemberExpression firstOrDefaultParameterO = Expression.Property(expression, typeof(Example).GetProperty("Name"));
问题是我不知道如何绑定字符串类型,因为它没有 属性 会给出 属性 值。
顺便说一句:collectionValuesType = typeof(string)
我已经按照建议编辑了问题以使事情更清楚。
您不需要为字符串等简单类型构造 Expression.Property。
例如。如果我必须为类型 Person
和 Name
属性 的 OrderBy 方法构建表达式树,我将像这样构建表达式树:
ParameterExpression pe = System.Linq.Expressions.Expression.Parameter(typeof(T), "p");
Expression<Func<T, TPropertyType>> expr = System.Linq.Expressions.Expression.Lambda<Func<T, TPropertyType>>(System.Linq.Expressions.Expression.Property(pe, propertyName), pe);
但对于字符串类型,我将简单地做:(因为对于字符串类型,您的表达式将只是 x=>x)
If( typeof(T)==typeof(string))
{
ParameterExpression pe = System.Linq.Expressions.Expression.Parameter(typeof(T), "p");
Expression<Func<T, TPropertyType>> expr = System.Linq.Expressions.Expression.Lambda<Func<T, TPropertyType>>(pe,pe);
}
您或许可以使用相同的概念来解决您的问题。
天哪,我浪费了一整天的时间,因为我最后在 Expression.Call 传递了错误的参数。
return Expression.Call(
firstOrDefaultMethod,
expression,
Expression.Lambda(firstOrDefaultDelegateType, firstOrDefaultCompareExpression,
//THIS IS THE PROBLEM, it should be "firstOrDefaultPredicateParameter"
Expression.Parameter(collectionValuesType))
);
@ANewGuyInTown 感谢您的帮助,在查看您的回答后我在我的代码中做了 "full scan" 并发现了这个错误
我正在尝试创建一个表达式,该表达式将 FirstOrDefault 与 IEnumerable<TComparable>
表达式的谓词一起使用,但它给了我这个错误:
参数 'o' 未绑定到指定的 LINQ to Entities 查询表达式
我有一个这样的 linq 表达式:
IEnumerable<string> names = new List<string>() { "abc", "def", "ghi" };
string name = names.FirstOrDefault(o => o.Contains("abc"));
public static Expression FirstOrDefault(this Expression expression, Type collectionValuesType, MethodInfo comparerMethod, string keyword)
{
MethodInfo firstOrDefaultMethod = typeof(Enumerable).GetMethods()
.FirstOrDefault(o => o.Name == "FirstOrDefault" && o.GetParameters().Length == 2)
.MakeGenericMethod(new Type[] { collectionValuesType });
Type firstOrDefaultDelegateType = typeof(Func<,>).MakeGenericType(collectionValuesType, typeof(bool));
ParameterExpression firstOrDefaultPredicateParameter = Expression.Parameter(collectionValuesType);
//THIS LINE binds the "o" in (o => o.Contains("abc")) , and it is where I'm stuck with since yesterday!
MemberExpression firstOrDefaultParameterO = Expression.Property(expression, typeof(string).GetProperty(???));
//o => o.ComparerMethod(keyword)
MethodCallExpression firstOrDefaultCompareExpression = Expression.Call(
firstOrDefaultParameterO,
comparerMethod,
Expression.Constant(keyword, typeof(string))
);
//expression.FirstOrDefault(firstOrDefaultCompareExpression);
return Expression.Call(
firstOrDefaultMethod,
expression,
Expression.Lambda(firstOrDefaultDelegateType, firstOrDefaultCompareExpression, Expression.Parameter(collectionValuesType))
);
}
如果我有一个复杂的类型,我会这样使用:
public class Example { public string Name; }
//o => o.Name.Contains("abc"))
MemberExpression firstOrDefaultParameterO = Expression.Property(expression, typeof(Example).GetProperty("Name"));
问题是我不知道如何绑定字符串类型,因为它没有 属性 会给出 属性 值。
顺便说一句:collectionValuesType = typeof(string)
我已经按照建议编辑了问题以使事情更清楚。
您不需要为字符串等简单类型构造 Expression.Property。
例如。如果我必须为类型 Person
和 Name
属性 的 OrderBy 方法构建表达式树,我将像这样构建表达式树:
ParameterExpression pe = System.Linq.Expressions.Expression.Parameter(typeof(T), "p");
Expression<Func<T, TPropertyType>> expr = System.Linq.Expressions.Expression.Lambda<Func<T, TPropertyType>>(System.Linq.Expressions.Expression.Property(pe, propertyName), pe);
但对于字符串类型,我将简单地做:(因为对于字符串类型,您的表达式将只是 x=>x)
If( typeof(T)==typeof(string))
{
ParameterExpression pe = System.Linq.Expressions.Expression.Parameter(typeof(T), "p");
Expression<Func<T, TPropertyType>> expr = System.Linq.Expressions.Expression.Lambda<Func<T, TPropertyType>>(pe,pe);
}
您或许可以使用相同的概念来解决您的问题。
天哪,我浪费了一整天的时间,因为我最后在 Expression.Call 传递了错误的参数。
return Expression.Call(
firstOrDefaultMethod,
expression,
Expression.Lambda(firstOrDefaultDelegateType, firstOrDefaultCompareExpression,
//THIS IS THE PROBLEM, it should be "firstOrDefaultPredicateParameter"
Expression.Parameter(collectionValuesType))
);
@ANewGuyInTown 感谢您的帮助,在查看您的回答后我在我的代码中做了 "full scan" 并发现了这个错误