linq - 使用在运行时解析的类型调用 System.Linq.Queryable 方法

标签 linq generics reflection dynamic c#-4.0

我正在构建一个基于 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<Customer,anonymous type>而不是 Func<Customer, object> :
//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 ...

如果仔细观察,它会错误地推断通用参数:Customer,object而不是 Customer,anonymous type ,这是 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失败是匿名类型被定义为 internal .这就是为什么它使用概念验证项目工作的原因,其中所有内容都在同一个程序集中。

我很酷。我仍然想找到一种更简洁的方法来找到正确的 Queryable.Select重载。

最佳答案

修复方法很简单,很伤人:

[assembly: InternalsVisibleTo("My.Search.Lib.Assembly")]

关于linq - 使用在运行时解析的类型调用 System.Linq.Queryable 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5438929/

相关文章:

c# - 如何将 XmlIncludeAttribute 应用于 TypeBuilder?

c# - OrderBy().Last() 或 OrderByDescending().First() 性能

c# - 如何在查询 C# 中使用 Linq 和 Dictionary 从 List<> 获取元素?

java - 避免与 Kotlin 泛型内联

java - <T 扩展是什么意思?

Java:带反射的工厂方法?

java - 如何以编程方式检查哪个 sim 卡被设置为 android 中的默认 sim 卡

c# - Entity Framework .load(MergeOption) 做什么?

c# - 如何使用 LINQ 对从文件加载的数据进行排序

C# 方法重载解析不选择具体的泛型覆盖