2013-02-14 8 views
18

System.Linq.ILookUp definicja brzmiCzy ILookup <TKey, TElement> nie powinien być (zadeklarowany) kowariantem w TElement?

interface ILookup<TKey, TElement> : IEnumerable<IGrouping<TKey, TElement>>, IEnumerable { 
    int Count { 
     get; 
    } 

    IEnumerable<TElement> this[TKey key] { 
     get; 
    } 

    bool Contains(TKey key); 
} 

Od IEnumerable jest kowariantna w IGrouping < TKey, TElement >, IGrouping < TKey, TElement > jest kowariantna w TElement a interfejs tylko naraża TElement jako typ zwracany, Zakładam, że ILookup jest również kowariancyjny w TElement. Rzeczywiście, kompilacja bez problemów jest zdefiniowana.

Co może być przyczyną braku słowa kluczowego poza w pierwotnej definicji? Czy można dodać przyszłe wersje Linq?

+1

... nikt nie myślał o, projektował, wdrażał, testował, wypuszczał ... a może z zupełnie innego powodu. –

+0

Cóż, właśnie się zastanawiałem, czy to już cała historia. Z drugiej strony, jestem ciekawy, czy takie przypadki są a) wspólne b) prawdopodobnie będzie _fixed_ w przyszłości – bigge

+0

LINQ został wprowadzony w .NET Framework 3.5 (C# 3.0), natomiast wariancja dla ogólnych parametrów typu w interfejsach od C# 4.0 . Czy to może być powód? –

Odpowiedz

7

Śledzenie dokumentacji MSDN, Covariance and Contravariance in Generics zostało wprowadzone w .NET Framework 4 Poprzednio istniała IEnumerable<T> od .NET Framework 2.0 do .NET Framework 3.5. Następnie w .NET Framework 4.0 możemy zobaczyć IEnumerable<out T> z parametrem typu T jako kowariancją.

IGrouping<TKey, TElement> i ILookup<TKey, TElement> istniały od .NET Framework 3.5. W programie .NET Framework 4.0 ten pierwszy został zaktualizowany do wersji IGrouping<out TKey, out TElement>, ale ten ostatni został pominięty bez podania przyczyny.

TKey nie może być kowariantem, ponieważ uniemożliwiają to implementacje Contains(TKey) i .

W odniesieniu do TElement problem nie jest jasny. Nie wierzę, że projektanci po prostu to przegapili. Być może przyczyna leży w planach na przyszłość. Albo chcieli zapobiec coś jak poniżej, ale nie wiem dlaczego:

string[] strings = new[] {"a", "a", "b", "b", "b", "c"}; 
ILookup<string, string> lookup = strings.ToLookup(s => s); // Valid. 
ILookup<string, object> lookup = strings.ToLookup(s => s); // Now invalid, but would correct if TElement was covariant (out TElement). 

Istnieją również inni autorzy, które zwracają uwagę na ten temat:

ToLookup:

Należy zauważyć, że choć IGrouping jest kowariancyjny w TKey i TElement, ILookup jest niezmienny w obu parametrach typu. O ile TKey musi być niezmienny, byłoby uzasadnione, aby TElement był kowariantem

+0

Naprawdę ładna odpowiedź, dzięki. Nawet jeśli nie odpowiada to bezpośrednio na moje pytanie, twoja odpowiedź pokazuje, że jest tu problem (nawet jeśli jest mały). Zaakceptowałem twoją odpowiedź, ponieważ prawdopodobnie wszyscy mogą dowiedzieć się o problemie. +1 za znalezienie oferty. – bigge

+0

@bigge: Dziękuję za docenienie mojego czasu. Miałem na myśli tę sprawę. Jeśli znajdę coś nowego, dodam go do odpowiedzi. –

+0

Kiedy mówisz "zapobiec coś podobnego" poniżej, co masz na myśli? Określasz, że oba połączenia typu "ToLookup" są legalne (jeden "OK" i jeden "Prawny"). O co chodzi, jeśli wszystko działa? –

Powiązane problemy