C#泛型方法类型约束到几个类

时间:2013-05-30 13:37:22

标签: c# generics linq-to-entities

我有这样的事情:

    public List<T> GetPageRows<T>(Expression<Func<T, bool>> predicate, List<ColumnSortOrder> sortOrder, int pageSize, int pageNo) where T : Type1, Type2, Type3
    {
        var filteredQueryable = GetRowsAndFilter(predicate);
        var orderedQueryable = GetOrderedQueryable(sortOrder, filteredQueryable);
        var pagedQueryable = orderedQueryable.Skip((pageNo - 1) * pageSize).Take(pageSize);
        return pagedQueryable.ToList();
    }

    private IQueryable<Type1> GetRowsAndFilter(Expression<Func<Type1, bool>> predicate)
    {
        return GetType1s(predicate);
    }

    private IQueryable<Type2> GetRowsAndFilter(Expression<Func<Type2, bool>> predicate)
    {
        return GetType2s(predicate);
    }

    private IQueryable<Type3> GetRowsAndFilter(Expression<Func<Type3, bool>> predicate)
    {
        return GetType3s(predicate);
    }

我希望通过制作GetRowsAndFilter()的非泛型类特定版本,然后将GetPageRows()的泛型类型参数限制为这三个类中的一个,编译器能够弄清楚要做什么。

where T : Type1, Type2, Type3似乎是非法的。

我该如何解决这个问题?

这个想法是GetPageRows()中的算法是通用的,并不依赖于我得到的特定类型的行。只有返回类型和谓词取决于T.

编辑:我尝试限制他们的基本类型以及常见的空接口,但我仍然在var filteredQueryable = GetRowsAndFilter(predicate);中收到错误。 “无法解决方法”。它不知道如何选择这些方法的正确版本。我不知道该怎么办。应该可以将GetPageRows()中的通用算法与实际类型T以及GetRowsAndFilter()的不同版本中每个T的特定不同查询分开。

3 个答案:

答案 0 :(得分:2)

虽然您可以使用空接口来解决多个约束来指定一个约束,但这不能解决您的问题:无法正确解析GetRowsAndFilter

稍微弯曲代码之后,我想出了这个存根(我改变并剪切了东西以便编译,但你应该能够将相同的概念应用到你的代码中):

    static void Main(string[] args)
    {
       var res = GetPageRows<Type1>(GetRowsAndFilter, t => true, null, 0, 0);
       var res2 = GetPageRows<Type2>(GetRowsAndFilter, t => true, null, 0, 0);

        Console.ReadLine();
    }

    public static List<T> GetPageRows<T>(Func<Expression<Func<T, bool>>, IEnumerable<T>> getRows, Expression<Func<T, bool>> predicate, List<int> sortOrder, int pageSize, int pageNo)
    {
        var filteredQueryable = getRows(predicate);
        return filteredQueryable.ToList();
    }

    private static IEnumerable<Type1> GetRowsAndFilter(Expression<Func<Type1, bool>> predicate)
    {
        return Enumerable.Empty<Type1>();
    }

    private static IEnumerable<Type2> GetRowsAndFilter(Expression<Func<Type2, bool>> predicate)
    {
        return Enumerable.Empty<Type2>();
    }

    private static IEnumerable<Type3> GetRowsAndFilter(Expression<Func<Type3, bool>> predicate)
    {
        return Enumerable.Empty<Type3>();
    }

您还需要提供调用的方法,否则编译器无法解析它,因为它没有足够的关于T的类型信息,通过提供方法并使其使用相同的泛型类型方法签名,编译器至少可以确保方法正在谈论相同的T。在调用方(GetPageRows<Type1>())上,指定类型是其余要正确解析的驱动程序。

答案 1 :(得分:1)

由于C#中无法进行多重继承,因此除非Type1Type2Type3中的任何一个不是接口,否则不能这样做。如果Type1Type2Type3中不止一个不是接口,则无法满足约束条件。此外,接口必须在类型约束的排序中排在最后。

你可能会说,等等,如果Type3 : Type2 : Type1怎么办?在这种情况下,我们仍然可以T满足Type1但不满足Type2Type3。因此,在这种情况下,我们从编写Type1, Type2, Type3获得的任何内容都不会因为它本身等同于Type3

答案 2 :(得分:0)

明确地指定这三种不同的类型是直觉错误的:你如何知道,在编译时安全地输入类型,你正在使用哪种类型?定义它们全部派生的公共基类或它们都实现的接口,并将泛型参数类型约束到最小公分母。