在泛型类型参数上调用扩展方法(例如“Union”)

时间:2013-12-02 20:03:37

标签: c# .net generics extension-methods

我们正在尝试构建一个采用泛型类型参数的库例程。我们遇到了一个问题,即无论我们如何约束类型,扩展方法“Union”都不会被识别为对一般类型参数有效。

这是一个简单,大大简化的例子来说明问题:

private IQueryable<int> Test(IQueryable<int> temp1, IQueryable<int> temp2)
{
    return temp1.Union(temp2); // compiles fine
}

private T Test<T>(T temp1, T temp2) where T : IQueryable
{
    return temp1.Union(temp2); // Error 15  'T' does not contain a definition for 'Union' and no extension method 'Union' accepting a first argument of type 'T' could be found
}

问题似乎是Union被实现为IQueryable的扩展方法,而不是作为IQueryable接口本身的一部分。似乎必须有一个相当简单的方法来完成这项工作,但我一直在通过StackOverflow和Google查看,没有任何运气。任何帮助非常感谢。

=================================

编辑:

这确实会编译:

private IQueryable<T> Test<T>(IQueryable<T> temp1, IQueryable<T> temp2)
{
    return temp1.Union(temp2); // compiles fine
}

然而,这并没有得到我真正的问题,这就是为什么扩展方法在泛型类型参数上无法识别的原因。这个解决方案简单地消除了(如上所述,大大简化)示例的关键点中的“泛型主义”。我认为,正如一个答案所指出的,IQueryableIQueryable<>之间的区别确实很重要。

为了记录,我也尝试过:

private C<T> Test<C, T>(C<T> temp1, C<T> temp2) // The type parameter 'C' cannot be used with type arguments
{
    return temp1.Union(temp2);
}

这会给出编译错误。

3 个答案:

答案 0 :(得分:4)

代码无法编译,因为它无法编译:

IQueryable a, b;
a.Union(b);

因为Union适用于IQueryable<T>,而不是IQueryable

IQueryable<TItem> Test<T, TItem>(T temp1, T temp2) where T : IQueryable<TItem>
{
    return temp1.Union(temp2);
}

您需要使其成为界面的通用版本并指定项目类型。返回类型不能为T,因为Union未返回T,而是返回IQueryable<TItem>

事实上,我认为你的意思是:

IQueryable<TItem> Test<TItem>(IQueryable<TItem> temp1, IQueryable<TItem> temp2)
{
    return temp1.Union(temp2);
}

哪个更简单。

答案 1 :(得分:1)

继承某些内容与实现某些内容之间存在差异,问题更像是您应该实现的composition over inheritance

 IQueryable<T>

答案 2 :(得分:0)

我在这里想知道的根本问题是扩展方法未被识别的原因。感谢“usr”的回答,指出了方向。我没有考虑IQueryableIQueryable<T>之间的区别。一旦我开始讨论这个问题,我就能找到我想要的真正答案,这似乎如下(再次,这是一个简单的实现,但它实现了我之后的原则):

    private C Test<C, T>(C temp1, C temp2) where C : IQueryable<T>
    {
        return (C)temp1.Union(temp2); // compiles fine
    }

感谢大家的帮助!