IQueryable.GroupBy覆盖int和bool的抛出,但不覆盖字符串

时间:2012-03-19 16:42:01

标签: c# .net linq nhibernate generics

我有一个关于IQueryable的扩展方法的初稿,它有一个GroupBy的覆盖,它应该由一个命名属性分组。

在你提问之前,我没有使用Dynamic Expression API,即动态Linq,因为我无法弄清楚如何使用它来访问每个组的计数。该库中的GroupBy方法返回非泛型IQueryable,而不是我需要的IQueryable<IGrouping<>>。如果有办法通过该库获取计数,我将很乐意接受一个答案,告诉我如何。也许某种语法我找不到string elementSelector参数中的文档?

代码:

    public static IQueryable<IGrouping<object, T>> GroupBy<T>(this IQueryable<T> source, string propertyName)
    {
        ParameterExpression param = Expression.Parameter(typeof(T), String.Empty);
        MemberExpression property = Expression.PropertyOrField(param, propertyName);
        LambdaExpression group = Expression.Lambda(property, param);

        MethodCallExpression call = Expression.Call(
            typeof(Queryable),
            "GroupBy",
            new[] { typeof(T), property.Type },
            source.Expression,
            Expression.Quote(group));

        return source.Provider.CreateQuery<IGrouping<object, T>>(call);
    }

我这样消耗它:

    public IEnumerable<Category> GetCategories(IQueryable<T> entities, string property)
    {
        var haba = entities.GroupBy(property);
        var categories = haba.Select(group => new Category(group.Key.ToString(), group.Count()));
        return categories.ToArray();
    }

只要我的属性是string类型,它就可以正常工作。但是,如果我尝试在int或bool属性上使用它,我会在调用CreateQuery时遇到以下错误:

  

参数表达式有类型   System.Linq.IQueryable 1[System.Linq.IGrouping 2 [System.Int32,DerivedEntity1]]   当类型   System.Collections.Generic.IEnumerable 1[System.Linq.IGrouping 2 [System.Object的,DerivedEntity1]]   预计。参数名称:表达式

我注意到它期待IEnumerable泛型而不是IQueryable,这很奇怪。但是一个非常好的提示。如果不执行IEnumerable,则无法将IQueryable投射到AsQueryable()。那么问题是,为什么它会给我一个IEnumerable而不是IQueryable?当我传入一个字符串属性的propertyName时,为什么它不会以同样的方式失败?

我应该提一下,我的IQueryableNhQueryable的实例,来自NHibernate,就是这样。

2 个答案:

答案 0 :(得分:2)

我认为您的代码中缺少来自值类型的装箱:

public static IQueryable<IGrouping<object, T>> GroupBy<T>(this IQueryable<T> source, string propertyName)
{
    ParameterExpression param = Expression.Parameter(typeof(T), String.Empty);
    MemberExpression property = Expression.PropertyOrField(param, propertyName);
    UnaryExpression convert = Expression.Convert(property, typeof(object));
    LambdaExpression group = Expression.Lambda(convert, param);

    MethodCallExpression call = Expression.Call(
        typeof(Queryable),
        "GroupBy",
        new[] { typeof(T), typeof(object) },
        source.Expression,
        Expression.Quote(group));

    return source.Provider.CreateQuery<IGrouping<object, T>>(call);
}

答案 1 :(得分:0)

您是否尝试过更改方法定义以包含其他类似的通用类型

public static IQueryable<IGrouping<O, T>> GroupBy<O, T>(this IQueryable<T> source, string propertyName)
{    
   return source.Provider.CreateQuery<IGrouping<O, T>>(call);

}
消费它像:

var haba = entities.GroupBy<int, Category>(property);