2011-02-05 21 views
18

zauważyłem to na drugi dzień, że masz dwie przeciążone metody:Sposób w odniesieniu do leków generycznych i IEnumerable

public void Print<T>(IEnumerable<T> items) { 
    Console.WriteLine("IEnumerable T"); 
} 
public void Print<T>(T item) { 
    Console.WriteLine("Single T"); 
} 

ten kod:

public void TestMethod() { 
    var persons = new[] { 
     new Person { Name = "Yan", Age = 28 }, 
     new Person { Name = "Yinan", Age = 28 } 
    }; 
    Print(persons); 
    Print(persons.ToList()); 
} 

drukuje:

Single T 
Single T 

Dlaczego numery Person[] i List<Person> są lepiej dopasowane do T niż w tych przypadkach są one IEnumerable<T>?

Dzięki,

UPDATE: Ponadto, jeśli masz inny przeciążenie

public void Print<T>(List<T> items) { 
    Console.WriteLine("List T"); 
} 

Print(persons.ToList()); rzeczywiście drukuje List T zamiast Single T.

+2

Wywołanie "Print (persons as IEnumerable );" powinno wywołać inną metodę.Ogólne wyszukiwanie metody nie wykonuje niejawnego rzutowania z 'Person []' na 'IEnumerable '. Kiedy wywołujesz 'person.ToList()', twoim bezpośrednim typem jest 'List ' (również nie wymaga niejawnego rzutowania). –

+0

+1 Przez jakiś czas błąkałem się z tym problemem. – Dan

Odpowiedz

17

Pierwsza część twojego pytania (bez przeciążenia specyficznego dla List) jest łatwa. Rozważmy wywołanie Array, ponieważ działa ono tak samo dla obu wywołań:

Najpierw, wnioskowanie typu tworzy dwie możliwe ogólne implementacje połączenia: Print<Person[]>(Person[] items) i Print<Person>(IEnumerable<Person> items).

Następnie rozdzielczość przeładowania zostaje uruchomiona, a pierwsza wygrywa, ponieważ druga wymaga niejawnej konwersji, w której pierwsza nie występuje (patrz § 7.4.2.3 specyfikacji C#). Ten sam mechanizm działa dla wariantu List.

Po dodaniu przeciążenia generowane jest trzecie możliwe przeciążenie z wywołaniem listy: Print<Person>(List<Person> items). Argument jest taki sam jak w przypadku Print<List<Person>>(List<Person> items) ale znowu, sekcja 7.4.3.2 zapewnia rozdzielczość z językiem

rekurencyjnie, skonstruowaną typ jest bardziej szczegółowy niż innym skonstruowanego typu (z taką samą liczbą argumentów typu), jeżeli co najmniej jeden argument typu jest bardziej szczegółowy i żaden argument typu nie jest mniej dokładny niż odpowiadający mu argument typu w drugim.

więc przeciążenie Print<Person> jest bardziej szczegółowy niż przeciążenia Print<List<Person>> a wersja Lista wygrywa nad IEnumerable ponieważ nie wymaga niejawna konwersja.

+0

dzięki za wzmiankę o niejawnym castingu, teraz wszystko ma sens – theburningmonk

3

Ponieważ metody generowane przez generyczne modele Print(Person[] item) i Print(List<Person> item) są lepiej dopasowane niż IEnumerable<T>.

Kompilator generuje te metody oparte na swoich argumentów typu, więc ogólny szablon Print<T>(T item) dostanie skompilowany jako Print(Person[] item) i Print(List<Person> item) (dobrze, niezależnie od typu reprezentuje List<Person> przy kompilacji). Z tego powodu wywołanie metody zostanie rozwiązane przez kompilator jako konkretna metoda akceptująca typ bezpośredni, a nie implementacja Print(IEnumerable<Peson>).

+0

innymi słowy, drukowanie zawsze będzie uważane za najlepsze dopasowanie, ponieważ T może być cokolwiek? Ale jeśli dodasz metodę Print (List items), jest to metoda, która będzie wywoływana dla Print (persons.ToList). – theburningmonk

+0

Ponadto, zgodnie z tym postem na blogu Eric Lippert, to nie jest tak jak generics C# działa http://blogs.msdn.com/b/ericlippert/archive/2009/07/30/generics-are-not-templates.aspx to, co opisałeś, to szablony w C++ – theburningmonk

Powiązane problemy