2013-09-05 18 views
5

folgendes LinqPad Beispiel Gegeben:Warum benötigt IEnumerable keine Umwandlung, aber eine Liste?

void Main() 
{ 
    List<DbItem> dbItems = new List<DbItem> 
    { 
     new DbItem{Id = 4, SomeValue = "Value For 4", OtherValue = 1}, 
     new DbItem{Id = 19, SomeValue = "Value For 19", OtherValue = 2} 
    }; 

    ListMethod(dbItems.Cast<IDbItem>().ToList()); <-+ 
    EnumerableMethod(dbItems);      <-+ 
}              | 
                 | 
// These are the methods are I asking about -------+ 

public void ListMethod(List<IDbItem> dbItems) 
{ 
    Console.WriteLine(dbItems); 
} 
public void EnumerableMethod(IEnumerable<IDbItem> dbItems) 
{ 
    Console.WriteLine(dbItems); 
} 
public class DbItem : IDbItem 
{ 
    public int Id {get; set;} 
    public string SomeValue {get; set;} 
    public int OtherValue {get; set;} 
} 
public interface IDbItem 
{ 
    int Id {get; set;} 
    string SomeValue {get; set;} 
} 

Warum EnumerableMethod direkt die Liste nehmen kann, während ListMethod zuerst eine Besetzung braucht?

Ich bekomme, dass eine Besetzung von DbItem zu IDbItem passiert, aber was ist anders an der IEnumerable, die es ermöglicht, die Besetzung ohne eine ausdrückliche Anfrage zu machen?

Ich stelle mir vor, die Antwort beinhaltet das Wort Covariance, aber ich weiß nicht genug darüber, um es mir selbst herauszufinden.

Antwort

4

Auschecken this post about covariance. Er gibt eine Erklärung und eine Möglichkeit, den Code ohne die Besetzung funktionieren zu lassen. Listen sind nicht covariant, aber man kann einfach die Methode ändern, wie so:

public void ListMethod<T>(List<T> dbItems) where T : IDbItem 
{ 
    Console.WriteLine(dbItems); 
} 

Kovarianz ist die Fähigkeit, eine abgeleitete generischen Typ zu einer Basis generischer Typ zuzuordnen. Der Grund List nicht kovariant ist, weil Sie dies tun könnte:

class Animal {} 
class Dog : Animal {} 
class Cat : Animal {} 

void someFunction() 
{ 
    List<Animal> dogs = new List<Dog>(); 
    dogs.Add(new Cat()); 
} 

dogs ist wirklich eine Liste von Hunden, nicht von Tieren. Daher wäre das Hinzufügen eines Cat ein Problem, das speziell einen Compilerfehler verursacht.

+0

ich, dass ein Hund ist wirklich eine Liste von Hunden und nicht Tiere. Aber warum funktioniert es für IEnumerable? – Vaccano

+0

'IEnumerable' hat keine 'Add'-Methode, so dass man keine Angst hat,' 'Katze'' zu' Hunden' hinzuzufügen. Kovarianz ist etwas, das explizit angegeben werden muss, und die Leute, die 'List' gemacht haben, entschieden, dass es aus dem oben genannten Grund nicht kovariant sein sollte. Die Leute, die "IEnumerable" gemacht haben, entschieden, dass es kovariant sein sollte. – ShadowCat7

0

Weil Sie keine Sammlung von xs in eine Sammlung von ys schreiben können, obwohl x von y abgeleitet ist und daher jedes x ein y ist. Siehe this SO question.

Aus diesem Grund wurden die Konzepte Kovarianz und Contravarianz der Sprache hinzugefügt.

Leider unterstützt List<T> diese Funktionen nicht.

+0

.NET 4.0/C# 4.0 gilt nur für generische Schnittstellen und generische Delegatendeklarationen; Es gilt nicht für Betontypen (es ist also kein Unterstützungsmerkmal von List, sondern von allen konkreten Typen). –

3

ich die Antwort vorstellen, das Wort Kovarianzstrukturen

beinhaltet Ja, Sie richtig sind, der Typ-Parameter für IEnumerable<T> kovariant. so können Sie entweder den Typ verwenden Sie jede Art angegeben oder die mehr

abgeleitet
public interface IEnumerable<out T> : IEnumerable 

Wo als List<T> Typparameter nicht kovariant ist

public class List<T> : IList<T>, ICollection<T>, 
    IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>, IEnumerable<T>, 
    IEnumerable 
+0

Macht das Schlüsselwort 'out' IEnumerable covariant? Wenn ja warum? Wenn nicht, was dann? – Vaccano

+0

Ja, der out macht den Typparameter kovariant, warum? Das ist eine Frage für die C# -Sprachdesigner –

Verwandte Themen