IQueryable.GroupBy重写为int和bool抛出,但不为字符串抛出

本文关键字:字符串 bool 重写 GroupBy int IQueryable 抛出 | 更新日期: 2023-09-27 18:28:28

我有一个IQueryable上的扩展方法的初稿,其中包含GroupBy的重写,该重写应按命名属性分组。

在你提问之前,我没有使用动态表达式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();
    }

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

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

我注意到它期望的是IEnumerable泛型,而不是IQueryable,这很奇怪。但这是个不错的建议。如果不执行AsQueryable(),就无法将IEnumerable强制转换为IQueryable。那么问题是,为什么它给我一个IEnumerable而不是IQueryable?为什么当我为字符串属性传递propertyName时,它不会以同样的方式失败?

我应该提到我的IQueryable是来自NHibernate的NhQueryable的实例,也就是

IQueryable.GroupBy重写为int和bool抛出,但不为字符串抛出

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

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

您是否尝试更改方法定义以包含另一个泛型类型,如so

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