Benutzer mit den meisten Antworten
Typecast auf ein generisches Objekt?

Frage
-
Hallo zusammen,
ich arbeite derzeit mit einer externen Bibliothek, die recht allgemein gehalten ist und bei vielen Methoden einfach nur "object" zurück gibt. Darum hat sich jetzt folgende Situation ergeben:
object theObjectToCast = /* Bibliotheks-Aufruf */; IEnumerable<object> collection = (/* hier! */)theObjectToCast; foreach(object content in collection){ // hier soll es weitergehen }
Ich weiß ganz genau (aufgrund der API-Dokumentation der Bibliothek und meinem Parameter beim Aufruf) dass das "theObjectToCast" das Interface "IEnumerable" implementiert. Den generischen Typ-Parameter kenne ich allerdings nicht, darum verwende ich "object".
Wenn ich allerdings versuche, das /* hier! */ mit einem direkten Cast auf IEnumerable<object> zu ersetzen, erhalte ich einen Laufzeit-Fehler.
Meine Frage also: wie kann ich einen generischen Typ auf ein generisches Interface casten, sodass das generische Interface als Typ-Parameter einfach nur "object" hat?
Gruß,
Alan
PS: Tut mir leid falls meine Formulierung etwas schwammig ist, ich kenne Generics bislang nur von Java, und dort läuft es ja total anders.
Antworten
-
Hallo zusammen,
wenn das Problem eine InvalidCastException ist, würde ich einfach auf System.Collections.IEnumerable casten (da IEnumerable<T> sowieso die Schnittstelle IEnumerable implementiert).
Gruß
Marcel- Als Antwort markiert Alan_1989 Donnerstag, 25. April 2013 13:58
Alle Antworten
-
Hallo, eigentlich ganz einfach:
IEnumerable<string> test = new List<string>() { "Item1", "Item2" }; object some = test; IEnumerable<object> someObjects = (IEnumerable<object>)some; foreach (object item in someObjects) Console.WriteLine(item.ToString()); Console.ReadKey();
Wenn du sowieso weißt das das object das Interface implementiert, dann kannst du doch auch ein IEnumerable<object> als T verlangen!?<Code:13/> - Koopakiller [kuːpakɪllɐ]
Webseite | Code Beispiele | Facebook | Snippets
Wenn die Frage beantwortet ist, dann markiert die hilfreichsten Beiträge als Antwort und bewertet die Beiträge. Danke.
Einen Konverter zwischen C# und VB.NET Code gibt es hier. -
Hallo zusammen,
wenn das Problem eine InvalidCastException ist, würde ich einfach auf System.Collections.IEnumerable casten (da IEnumerable<T> sowieso die Schnittstelle IEnumerable implementiert).
Gruß
Marcel- Als Antwort markiert Alan_1989 Donnerstag, 25. April 2013 13:58
-
Hallo Alan,
sollten die Antworten Dir geholfen haben, markiere Sie bitte als Antwort.
Grüße,
Stefan Kleinewillinghoefer, MICROSOFT
Bitte haben Sie Verständnis dafür, dass im Rahmen dieses Forums, welches auf dem Community-Prinzip „Entwickler helfen Entwicklern“ beruht, kein technischer Support geleistet werden kann oder sonst welche garantierten Maßnahmen seitens Microsoft zugesichert werden koennen.
-
Hallo zusammen,
vielen Dank für die Antworten! Ich war die letzten Tage viel auf Reisen und bin daher nicht dazu gekommen, das Problem weiter zu bearbeiten.
Ich konnte das Problem inzwischen beheben, indem ich die Lösung von Marcel Roma verwendet habe (vielen Dank dafür).
Allerdings ist mir noch nicht ganz klar, warum das so ist.
Ein Beispiel:
object obj = new Int16(); // das geht problemlos IEnumerable<object> hashSet = new HashSet<Int16>(); // typecast-Error wie oben beschrieben HashSet<object> test = new HashSet<Int16>(); // geht auch nicht
... und ich habe wirklich *keine* Ahnung warum das so ist. Kann mir irgendjemand auf die Sprünge helfen? Ich dachte immer, dass IEnumerable<T> kovariant ist?
EDIT: Ich habe es nach einigem Suchen in der Generics-FAQ von MSDN gefunden. Der Grund ist sehr simpel: in .NET 4 wird Kovarianz (und Varianz im Allgemeinen) für primitive Datentypen (wie Int16) nicht unterstützt.
- Bearbeitet Alan_1989 Donnerstag, 25. April 2013 14:23 Neue Erkenntnis gewonnen
-
Hallo Alan_1989,
ich sehe, Du hast die Erklärung inzwischen gefunden, hier noch ein kommentiertes Code-Snippet dazu:
// Hier wird ein Int16 einfach "geboxt" // Es findet keine Konvertierung statt. object obj = new Int16(); // Int16 ist ein Wertetyp. Kovarianz bezieht sich aber auf Referenztypen. // Schon deshalb kann hier keine Kovarianz inferiert werden. IEnumerable<object> targetGenericInterfaceHashSet = null; HashSet<Int16> sourceHashSet = new HashSet<Int16>(); // IEnumerable<object> befindet sich nicht in der Vererbungshierarchie von HashSet<Int16>. // IEnumerable<object> ist keine von HashSet<Int16> implementierte Schnittstelle. // HashSet<Int16> ist kein generischer Typparameter zu dem IEnumerable<object> eine Einschränkungen darstellt. // Also kann IEnumerable<object> auch nicht von HashSet<Int16> zugewiesen werden. if (typeof(IEnumerable<object>).IsAssignableFrom(typeof(HashSet<Int16>))) { // Ausführung erreicht diesen Codeblock nie. } else { // Die explizite Konversion von HashSet<Int16> geht beim Kompilieren durch try { targetGenericInterfaceHashSet = (IEnumerable<object>)new HashSet<Int16>(); } catch (InvalidCastException ice) { // wirft aber eine InvalidCastException zur Laufzeit, aus eben den o.g. Gründen. } } // Und wie sieht es mit einem Referenztyp aus? // String ist ein Referenztyp, daher funktioniert Kovarianz hier problemlos IEnumerable<object> hashSet2 = new HashSet<string>(); if (typeof(IEnumerable<object>).IsAssignableFrom(typeof(HashSet<String>))) { // Und siehe da: Zuweisbarkeit ist gegeben. } // Gleiches Problem wie oben: Wertetypen partizipieren nicht // in Varianz-Relationen, deshalb ist eine implizite Konversion // nicht möglich. Die explizite Konversion schlägt bereits zur // Kompilierzeit fehl, da Typsicherheit auf keinen Fall // sichergestellt werden kann. // HashSet<object> test = (HashSet<object>) new HashSet<Int16>();
Gruß
Marcel