Извикващ метод на разширение (напр. Union) на параметър от общ тип

Опитваме се да изградим библиотечна рутина, която приема параметър за общ тип. Сблъскахме се с проблем, при който методът на разширение „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
}

Това обаче не стига до истинския ми въпрос, поради което методите за разширение не бяха разпознати в параметъра с общ тип. Това решение просто премахва "generic-ism" в критичното място на (както беше отбелязано, силно опростен) пример. Мисля, че както отбелязва един отговор, е вярно, че разграничението между IQueryable и IQueryable<> е важно.

За протокола опитах и:

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

Това дава отбелязаната грешка на компилатора.


person Robert N    schedule 02.12.2013    source източник
comment
Защо гарантирате, че T прилага IQueryable, а не IQueryable<T>?   -  person Jon Hanna    schedule 03.12.2013


Отговори (3)


Кодът не се компилира, защото това също не се компилира:

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

Което е по-просто.

person usr    schedule 02.12.2013
comment
Благодаря, usr; Не мислех за разликата между IQueryable и IQueryable<T> - person Robert N; 03.12.2013

има разлика между наследяване от нещо и внедряване на нещо проблемът е по-скоро като композиция над наследяване трябва да внедрите

 IQueryable<T>
person BRAHIM Kamel    schedule 02.12.2013

Основният въпрос, за който се чудех тук, беше защо методите за разширение не бяха разпознати. Благодаря на отговора от "usr" за посочване на пътя. Не мислех за разликата между IQueryable и IQueryable<T>. След като се зарових с това, успях да намеря истинския отговор, който исках, който изглежда е както следва (отново, това е тривиална реализация, но прилага принципа, който преследвах):

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

Благодаря на всички за помощта!

person Robert N    schedule 02.12.2013