Деревья выражений - PullRequest
0 голосов
/ 11 мая 2018

У меня есть фрагмент кода ниже, и я получаю сообщение об ошибке, как указано ниже.

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: «Никакой универсальный метод« OrderBy »для типа« System.Linq.Queryable »не совместим с предоставленными аргументами и аргументами типа.Аргументы типа не должны предоставляться, если метод не является универсальным.'

Пожалуйста, объясните, что здесь не так?

1 Ответ

0 голосов
/ 12 мая 2018

Есть две "проблемы" с методом OrderBy: он имеет перегрузки и является общим. Сначала вам нужно выбрать правильную перегрузку:

var openOrderBy = typeof(Queryable)
    .GetMethods(BindingFlags.Static | BindingFlags.Public)
    .First(m => m.Name == "OrderBy" && m.GetParameters().Length == 2);

(примечание: здесь я использую простую проверку на основе количества параметров, вы можете прочитать больше здесь )

Тогда вам нужно привязать его к конкретным типам:

var closedOrderBy = openOrderBy.MakeGenericMethod(
    typeof(string), // type of item in collection, TSource
    typeof(string)); // type returned by lambda, TKey

Теперь вы можете использовать это MethodInfo в Expression.Call:

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));

Вы можете проверить это с помощью дополнительной лямбды:

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)
  );
...