Frage

Vor kurzem fand ich ein sehr überraschendes Verhalten in c #. Ich hatte eine Methode, die IEnumerable<Object> als Parameter annimmt und i vorging IEnumerable<string> aber es ist nicht möglich. Während in c # alles kann upcast als Objekt sein, warum dies nicht möglich ist? Es ist total verwirrend für mich. Bitte jemand mich klar zu diesem Thema.

War es hilfreich?

Lösung

Der Fachbegriff dafür ist, dass Generika invariant ist in C # 3.0 und früher. Von C 4.0 # Weiter arbeitet die Besetzung.

Was invariant Mittel ist, dass es keine Beziehung zwischen zwei generischen Typen, nur weil ihr generischer Typ Parametern beziehen (das heißt sind sub- oder übergeordnete Typen voneinander).

In Ihrem Beispiel gibt es keine Typisierung Beziehung zwischen einem IEnumerable<object> und einem IEnumerable<string>, nur weil Zeichenfolge ein Subtyp des Objekts ist. Sie sind nur zwei völlig unabhängige Arten betrachtet, wie eine Kette und ein int (sie noch beide Subtypen des Objekts, aber alles ist)

Es gibt ein paar Workarounds und Ausnahmen für dieses Problem, das Sie in ausgeführt haben.

Erstens können Sie jede Saite einzeln auf Objekt werfen, wenn Sie 3.0 .NET sind, können Sie tun, dass die Cast<T>() Erweiterung Methode. Ansonsten können Sie eine foreach verwenden und das Ergebnis in eine neue Variable vom statischen Typ wollen Sie setzen.

Zweitens Arrays sind eine Ausnahme für Referenztyp, das heißt in einer Zeichenkette passing [] Typ auf ein Verfahren acccepting Objekt [] Typen funktionieren sollen.

Andere Tipps

Wie andere haben darauf hingewiesen, Generika-Typen sind unveränderlich. IEnumerable<T> könnte kovarianten aber C # unterstützt derzeit keine Angabe Varianten. C # 4.0 wird erwartet, dass Varianten zu unterstützen, so könnte dies in Zukunft unterstützt werden.

Um dies zu umgehen können Sie jetzt eine der LINQ-Erweiterungsmethode Cast<object>() verwenden. Vorausgesetzt, dass Sie eine Methode namens Foo haben, die eine IEnumerable<object>> nimmt. Sie können es so nennen,

Foo(stringEnumerable.Cast<object>());

Der einfachste Weg, IEnumerable<string> passieren IEnumerable<object> zu funktionieren erfordert, ist durch Funktion wie diese Umwandlung:

public IEnumerable<object> convert<T>(IEnumerable<T> enumerable)
    {
    foreach (T o in enumerable)
        yield return o;
    }

Wenn C # 4 herauskommt, das wird nicht nötig sein, weil es Kovarianz und Kontra unterstützen wird.

Sie sollten werden mit

IEnumerable<T> 

, wenn Sie in verschiedenen Arten übergeben wollen, dann können Sie T abfragen, um herauszufinden, welche Art es ist.

Ein guter Weg, um darüber nachzudenken ist, sich zu fragen: „Was würde passieren, wenn Sie dies tun könnte?“. Nehmen Sie das folgende Beispiel:

IEnumerable<String> strings=...;
IEnumerable<Object> objects = strings; // assume this were legal

objects.Add(new Integer(5)); // what the...

Wir haben soeben eine ganze Zahl auf eine Liste von Strings. Der Compiler wird diese Art Sicherheit zu bewahren.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top