Ich kann nicht verstehen, warum der folgende C # -Code nicht kompiliert wird.
Wie Sie sehen können, habe ich eine statische generische Methode Etwas mit einem IEnumerable<T>
Parameter (und T
ist darauf beschränkt, eine IA
Schnittstelle zu sein), und dieser Parameter kann nicht implizit in konvertiert werden IEnumerable<IA>
.
Was ist die Erklärung? (Ich suche nicht nach einer Problemumgehung, nur um zu verstehen, warum es nicht funktioniert).
public interface IA { }
public interface IB : IA { }
public class CIA : IA { }
public class CIAD : CIA { }
public class CIB : IB { }
public class CIBD : CIB { }
public static class Test
{
public static IList<T> Something<T>(IEnumerable<T> foo) where T : IA
{
var bar = foo.ToList();
// All those calls are legal
Something2(new List<IA>());
Something2(new List<IB>());
Something2(new List<CIA>());
Something2(new List<CIAD>());
Something2(new List<CIB>());
Something2(new List<CIBD>());
Something2(bar.Cast<IA>());
// This call is illegal
Something2(bar);
return bar;
}
private static void Something2(IEnumerable<IA> foo)
{
}
}
Fehler, den ich in der Something2(bar)
Schlange bekomme :
Argument 1: Konvertierung von 'System.Collections.Generic.List' in 'System.Collections.Generic.IEnumerable' nicht möglich
c#
covariance
contravariance
BenLaz
quelle
quelle
T
auf Referenztypen beschränkt . Wenn Sie die Bedingung verwendenwhere T: class, IA
, sollte es funktionieren. Die verknüpfte Antwort enthält weitere Details.Something2(foo);
direkt sagen . Um dies zu verstehen, ist es nicht erforderlich.ToList()
, a zu ermittelnList<T>
(T
ist Ihr Typparameter, der von der generischen Methode deklariert wurde) (aList<T>
ist einIEnumerable<T>
).Antworten:
Die Fehlermeldung ist nicht ausreichend informativ, und das ist meine Schuld. Das tut mir leid.
Das Problem, das Sie haben, ist eine Folge der Tatsache, dass die Kovarianz nur bei Referenztypen funktioniert.
Sie sagen wahrscheinlich gerade "aber
IA
ist ein Referenztyp". Ja, so ist es. Aber du hast nicht gesagt, dassT
das gleich istIA
. Sie sagten, diesT
sei ein Typ, der implementiert wirdIA
, und ein Werttyp kann eine Schnittstelle implementieren . Daher wissen wir nicht, ob Kovarianz funktionieren wird, und wir verbieten es.Wenn die Kovarianz funktionieren soll, müssen Sie dem Compiler mitteilen, dass der Typparameter ein Referenztyp mit der
class
Einschränkung sowie derIA
Schnittstellenbeschränkung ist.Die Fehlermeldung sollte wirklich sagen, dass die Konvertierung nicht möglich ist, da für die Kovarianz eine Garantie für den Referenztyp erforderlich ist, da dies das grundlegende Problem ist.
quelle
customers.Select(c=>c.FristName)
? Die C # -Spezifikation ist sehr klar, dass dies ein Überlastungsauflösungsfehler ist: Der Satz anwendbarer Methoden mit dem Namen Select, der annehmen kann, dass das Lambda leer ist, ist leer. Aber die Hauptursache ist, dassFirstName
ein Tippfehler vorliegt.Ich wollte nur Erics exzellente Insider-Antwort mit einem Codebeispiel für diejenigen ergänzen, die mit allgemeinen Einschränkungen möglicherweise nicht so vertraut sind.
Ändern Sie
Something
die Signatur wie folgt: Dieclass
Einschränkung muss an erster Stelle stehen .quelle
primary_constraint ',' secondary_constraints ',' constructor_constraint
class
ist schlecht, weil es "Referenztyp" bedeutet, nicht "Klasse". Ich wäre glücklicher gewesen mit etwas Ausführlichem wiewhere T is not struct