Вызов методов System.Linq.Queryable с использованием типов, разрешенных во время выполнения

Я создаю генератор запросов на основе LINQ.

Одна из функций - возможность указывать произвольную проекцию на стороне сервера как часть определения запроса. Например:

class CustomerSearch : SearchDefinition<Customer>
{
    protected override Expression<Func<Customer, object>> GetProjection()
    {
        return x => new
                    {
                        Name = x.Name,
                        Agent = x.Agent.Code
                        Sales = x.Orders.Sum(o => o.Amount)
                    };
    }
}

Поскольку пользователь должен иметь возможность сортировать свойства проекции (в отличие от свойств клиента), я воссоздаю выражение как Func вместо ] Func :

//This is a method on SearchDefinition
IQueryable Transform(IQueryable source)
{
    var projection = GetProjection();
    var properProjection = Expression.Lambda(projection.Body,
                                             projection.Parameters.Single());

Чтобы вернуть спроектированный запрос, Я бы хотел иметь возможность сделать это (что, по сути, работает в почти идентичном доказательстве концепции):

return Queryable.Select((IQueryable<TRoot>)source, (dynamic)properProjection);

TRoot - это параметр типа в SearchDefinition. Это приводит к следующему исключению:

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:
The best overloaded method match for
'System.Linq.Queryable.Select<Customer,object>(System.Linq.IQueryable<Customer>,
 System.Linq.Expressions.Expression<System.Func<Customer,object>>)'
has some invalid arguments
   at CallSite.Target(Closure , CallSite , Type , IQueryable`1 , Object )
   at System.Dynamic.UpdateDelegates.UpdateAndExecute3[T0,T1,T2,TRet]
      (CallSite site, T0 arg0, T1 arg1, T2 arg2)
   at SearchDefinition`1.Transform(IQueryable source) in ...

Если присмотреться, общие параметры выводятся неправильно: Клиент, объект вместо Клиент, анонимный тип , который является фактическим типом выражение ProperProjection (проверено дважды)

Мое решение - использование отражения. Но с общими аргументами это настоящий беспорядок:

var genericSelectMethod = typeof(Queryable).GetMethods().Single(
    x => x.Name == "Select" &&
         x.GetParameters()[1].ParameterType.GetGenericArguments()[0]
          .GetGenericArguments().Length == 2);
var selectMethod = genericSelectMethod.MakeGenericMethod(source.ElementType,
                   projectionBody.Type);
return (IQueryable)selectMethod.Invoke(null, new object[]{ source, projection });

Кто-нибудь знает лучший способ?


Обновление : причина отказа dynamic заключается в том, что анонимные типы определены как внутренний . Вот почему он работал с использованием экспериментального проекта, где все было в одной сборке.

I ' Мне это нормально. Я все еще хотел бы найти более чистый способ найти правильную Queryable.Select перегрузку.

5
задан Diego Mijelshon 26 March 2011 в 01:55
поделиться