表达式树 OrderBy 异常
Expression Trees OrderBy Exception
我有以下代码片段并收到如下所述的错误。
string[] companies = {
"Consolidated Messenger", "Alpine Ski House", "Southridge Video", "City Power & Light",
"Coho Winery", "Wide World Importers", "Graphic Design Institute", "Adventure Works",
"Humongous Insurance", "Woodgrove Bank", "Margie's Travel", "Northwind Traders",
"Blue Yonder Airlines", "Trey Research", "The Phone Company",
"Wingtip Toys", "Lucerne Publishing", "Fourth Coffee"
};
var exp = companies.AsQueryable<string>();
// Compose the expression tree that represents the parameter to the predicate.
ParameterExpression pe = Expression.Parameter(typeof(string), "company");
// The IQueryable data to query.
IQueryable<String> queryableData = companies.AsQueryable<string>();
MethodCallExpression orderByCallExpression1 = Expression.Call(
typeof(Queryable),
"OrderBy",
new Type[] { queryableData.ElementType },
Expression.Lambda<Func<string, string>>(pe, new ParameterExpression[] { pe })
);
System.InvalidOperationException: 'No generic method 'OrderBy' on type
'System.Linq.Queryable' is compatible with the supplied type arguments
and arguments. No type arguments should be provided if the method is
non-generic. '
请指导这里有什么问题?
有两个 "problems" 和 OrderBy
方法:它有重载并且是通用的。首先你需要select纠正过载:
var openOrderBy = typeof(Queryable)
.GetMethods(BindingFlags.Static | BindingFlags.Public)
.First(m => m.Name == "OrderBy" && m.GetParameters().Length == 2);
(注意:这里我使用的是简单的基于参数计数的检查,你可以阅读更多here)
然后你需要将它绑定到具体类型:
var closedOrderBy = openOrderBy.MakeGenericMethod(
typeof(string), // type of item in collection, TSource
typeof(string)); // type returned by lambda, TKey
现在您可以在 Expression.Call
中使用 MethodInfo
:
var pe = Expression.Parameter(typeof(string), "company");
var orderByCall = Expression.Call(null, // for static methods
closedOrderBy,
companies.AsQueryable().Expression,
Expression.Lambda<Func<string, string>>(pe, pe));
你可以用额外的 lambda 测试它:
var result = Expression.Lambda<Func<IQueryable<string>>>(orderByCall)
.Compile().Invoke().ToList();
result.ForEach(Console.WriteLine);
更新: 正如@Ivan Stoev 在评论中所说,答案可以简化
var queryableData = companies.AsQueryable();
var pe = Expression.Parameter(typeof(string), "company");
var orderByCall = Expression.Call(typeof(Queryable),
"OrderBy",
new []{ queryableData.ElementType,
queryableData.ElementType }, // <-- fix #1 select correct overload
queryableData.Expression, // <-- fix #2 pass first argument
Expression.Lambda<Func<string, string>>(pe, pe)
);
我有以下代码片段并收到如下所述的错误。
string[] companies = {
"Consolidated Messenger", "Alpine Ski House", "Southridge Video", "City Power & Light",
"Coho Winery", "Wide World Importers", "Graphic Design Institute", "Adventure Works",
"Humongous Insurance", "Woodgrove Bank", "Margie's Travel", "Northwind Traders",
"Blue Yonder Airlines", "Trey Research", "The Phone Company",
"Wingtip Toys", "Lucerne Publishing", "Fourth Coffee"
};
var exp = companies.AsQueryable<string>();
// Compose the expression tree that represents the parameter to the predicate.
ParameterExpression pe = Expression.Parameter(typeof(string), "company");
// The IQueryable data to query.
IQueryable<String> queryableData = companies.AsQueryable<string>();
MethodCallExpression orderByCallExpression1 = Expression.Call(
typeof(Queryable),
"OrderBy",
new Type[] { queryableData.ElementType },
Expression.Lambda<Func<string, string>>(pe, new ParameterExpression[] { pe })
);
System.InvalidOperationException: 'No generic method 'OrderBy' on type 'System.Linq.Queryable' is compatible with the supplied type arguments and arguments. No type arguments should be provided if the method is non-generic. '
请指导这里有什么问题?
有两个 "problems" 和 OrderBy
方法:它有重载并且是通用的。首先你需要select纠正过载:
var openOrderBy = typeof(Queryable)
.GetMethods(BindingFlags.Static | BindingFlags.Public)
.First(m => m.Name == "OrderBy" && m.GetParameters().Length == 2);
(注意:这里我使用的是简单的基于参数计数的检查,你可以阅读更多here)
然后你需要将它绑定到具体类型:
var closedOrderBy = openOrderBy.MakeGenericMethod(
typeof(string), // type of item in collection, TSource
typeof(string)); // type returned by lambda, TKey
现在您可以在 Expression.Call
中使用 MethodInfo
:
var pe = Expression.Parameter(typeof(string), "company");
var orderByCall = Expression.Call(null, // for static methods
closedOrderBy,
companies.AsQueryable().Expression,
Expression.Lambda<Func<string, string>>(pe, pe));
你可以用额外的 lambda 测试它:
var result = Expression.Lambda<Func<IQueryable<string>>>(orderByCall)
.Compile().Invoke().ToList();
result.ForEach(Console.WriteLine);
更新: 正如@Ivan Stoev 在评论中所说,答案可以简化
var queryableData = companies.AsQueryable();
var pe = Expression.Parameter(typeof(string), "company");
var orderByCall = Expression.Call(typeof(Queryable),
"OrderBy",
new []{ queryableData.ElementType,
queryableData.ElementType }, // <-- fix #1 select correct overload
queryableData.Expression, // <-- fix #2 pass first argument
Expression.Lambda<Func<string, string>>(pe, pe)
);