Warum kann ich einer Liste der Betonoberfläche keine Liste konkreter Typen zuweisen?

8

Warum kompiliert das nicht?

%Vor%

Und wie erhalten Sie myList am schnellsten zum richtigen Typ?

BEARBEITEN Ich habe das DoStuffWithInterfaceList Beispiel vermasselt

    
JeremyWeir 20.11.2009, 19:04
quelle

8 Antworten

10

Die akzeptierte Lösung ist für große Listen ziemlich ineffizient und völlig unnötig. Sie können die Signatur Ihrer Methode so leicht ändern, dass der Code ohne Conversions funktioniert, entweder implizit oder explizit:

%Vor%

Beachten Sie, dass die Methode jetzt generisch ist und eine Typbeschränkung verwendet, um sicherzustellen, dass sie nur mit Listen von IConcrete subtypes aufgerufen werden kann.

    
Konrad Rudolph 21.11.2009, 08:55
quelle
16

Fast alle diese Antworten sagen, dass dies in C # 4 unterstützt wird. Sie sind alle falsch.

Nur um ganz klar zu sein: das ist kein Beispiel für die Kovarianz, die wir in C # 4 unterstützen werden, weil dies nicht typsicher wäre. Wir unterstützen typsichere Kovarianz und Kontravarianz von generischen Interfaces und Delegaten, die mit Reference-Type-Argumenten konstruiert sind . Das Beispiel verwendet hier einen Klassentyp, Liste, keinen Schnittstellentyp. Und der Schnittstellentyp IList ist nicht typsicher für Kovarianz oder Kontravarianz.

IEnumerable wird kovariant sein, da es eine Schnittstelle ist, die für die Kovarianz sicher ist.

    
Eric Lippert 20.11.2009 22:45
quelle
4

Gegenwärtig ist dies verboten, weil sonst die Typsicherheit gebrochen wäre.  Sie könnten so etwas in DoStuffWithInterfaceList tun:

%Vor%

Dies wird zur Laufzeit fehlschlagen, da listOfInterfaces nur vom Typ Concrete ist.

Wie andere bereits sagten, ist dies möglich, wenn Sie C # 4 nicht ändern, solange Sie die Liste in der Methode nicht ändern, sondern explizit dem Compiler mitteilen müssen.

Um Ihre andere Frage zum Konvertieren der Liste zu beantworten, Wenn Sie .Net 3.5 verwenden, würde ich mit Enumerable.Cast & lt; & gt; Erweiterungsmethode. Andernfalls können Sie selbst eine faule Konvertierungsmethode mit dem Schlüsselwort yield schreiben, wodurch Sie denselben Effekt erzielen.

BEARBEITEN:

Wie Eric Lippert sagte, sollten Sie IEnumerable verwenden, damit es in C # 4 funktioniert.

    
Moshe Levi 20.11.2009 19:13
quelle
2

Das hat mit Kovarianz und Kontravarianz zu tun. Eric Lippert hat Anfang des Jahres viel darüber geschrieben. (11 Blog-Einträge speziell zu diesem Thema.) Die erste ist Kovarianz und Kontravarianz in C #, Teil Eins . Lesen Sie das und suchen Sie seinen Blog für den Rest von ihnen. Er erklärt ausführlich, warum so etwas schwierig ist.

Gute Neuigkeiten: Einige Einschränkungen sind in C # 4.0 aufgehoben.

    
Jim Mischel 20.11.2009 19:09
quelle
2

IList würde nicht funktionieren, weil IList nicht kontravariant ist. Es muss IEnumerable sein, auch wenn dies nur in 4.0 funktioniert. Sie könnten auch einen ConvertAll mit einem Lambda-Ausdruck verwenden, der in 3.5 funktioniert.

    
spinon 20.11.2009 19:23
quelle
2

C # unterstützt zur Zeit keine Konvertierung generischer Typen ( wird in C # 4 unterstützt, wenn ich es richtig verstehe Wie wcoenen in Kommentaren unten sagt, und Eric erklärt auch in seiner Antwort, die Die einzige Möglichkeit, es in C # 4 zum Laufen zu bringen, ist IEnumerable<IConcrete> ). Vorläufig müssen Sie Ihre Liste in irgendeiner Weise konvertieren.

Sie können die Methode wie folgt aufrufen:

%Vor%

Aktualisieren
Ich habe bemerkt, dass du die Besetzung wahrscheinlich nicht in dem Lambda brauchst, obwohl ich es aus Gründen der Klarheit mag. Also sollte das auch funktionieren:

%Vor%     
Fredrik Mörk 20.11.2009 19:05
quelle
1

Sie könnten versuchen

%Vor%

aber ich denke, das funktioniert nur in .NET 4.0.

Wenn du dreckig sein willst, mach einfach

%Vor%

und überprüfen Sie, ob die herauskommenden Objekte konkret sind.

    
HaxElit 20.11.2009 19:08
quelle
0
%Vor%

oder

%Vor%

oder

%Vor%     
Daniel A. White 20.11.2009 19:07
quelle

Tags und Links