2016-07-21 17 views
2

Ich habe gelernt, dass HashSet die IEnumerable Schnittstelle implementiert. Somit ist es möglich, ein HashSet Objekt in IEnumerable implizit zu Stimmen:C# -Typ-Konvertierung: Explizite Umwandlung existiert, aber ein Konvertierungsfehler?

HashSet<T> foo = new HashSet<T>(); 
IEnumerable<T> foo2 = foo; // Implicit cast, everything fine. 

Diese für verschachtelte generische Typen funktioniert auch:

HashSet<HashSet<T>> dong = new HashSet<HashSet<T>>(); 
IEnumerable<IEnumerable<T>> dong2 = dong; // Implicit cast, everything fine. 

Zumindest ist das, was ich dachte. Aber wenn ich ein Dictionary machen, ich laufe in ein Problem:

IDictionary<T, HashSet<T>> bar = new Dictionary<T, HashSet<T>>(); 
IDictionary<T, IEnumerable<T>> bar2 = bar; // compile error 

Die letzte Zeile gibt mir die folgenden Compiler-Fehler (Visual Studio 2015):

kann nicht implizit Typen umwandeln

System.Collections.Generic.IDictionary<T, System.Collections.Generic.HashSet<T>> zu System.Collections.Generic.IDictionary<T, System.Collections.Generic.IEnumerable<T>>.

Eine explizite Konvertierung vorhanden ist (möglicherweise fehlt eine Guss?)

Aber wenn ich die Besetzung zu tun, indem er

IDictionary<T, IEnumerable<T>> bar2 = (IDictionary<T, IEnumerable<T>>) bar; 

dann bekomme ich eine ungültige Guss Ausnahme zur Laufzeit.

Zwei Fragen:

  • Wie das ich lösen? Ist der einzige Weg, um über die Schlüssel zu iterieren und ein neues Wörterbuch Stück für Stück aufzubauen?
  • Warum bekomme ich dieses Problem an erster Stelle, obwohl HashSet die Schnittstelle IEnumerable implementiert?
+0

'IEnumerable ' ist [covariant] (https://msdn.microsoft.com/en-gb/library/mt654060.aspx). 'IDictionary ' ist nicht. Es sind die * äußeren * Typen, wo dies wichtig ist –

Antwort

5

Der Grund ist es nicht der Fall funktioniert, dass der Wert in IDictionary<TKey, TValue> nicht co-variant ist (und noch ist der Schlüssel, aus den gleichen Gründen).Wenn es erlaubt wurden zu sein, dann würde dieser Code kompilieren, aber hat in Ausnahmefällen führen:

IDictionary<T, HashSet<T>> foo = new Dictionary<T, HashSet<T>>(); 
IDictionary<T, IEnumerable<T>> bar = foo; 
foo.Add(key, new List<T>()); 

Man sollte meinen, das Hinzufügen einer List<T> funktionieren würde, wie es der Werttyp gegeben kompilieren würde, ist angeblich IEnumerable<T>. Es kann jedoch nicht erfolgreich sein, da der tatsächliche Werttyp HashSet<T> ist.

Also ja: Der einzige Weg ist, ein neues Wörterbuch zu erstellen.

var bar = foo.ToDictionary(x => x.Key, x => x.Value.AsEnumerable()); 
3

Wie löse ich das? Ist die einzige Möglichkeit, über die Schlüssel zu iterieren und ein neues Wörterbuch Stück für Stück aufzubauen?

Es ist vielleicht nicht die eleganteste Lösung, aber es funktioniert:

IDictionary<T, HashSet<T>> bar = new Dictionary<T, HashSet<T>>(); 
IDictionary<T, IEnumerable<T>> bar2 = bar.ToDictionary(x => x.Key, y => (IEnumerable<T>)y.Value); 

Der Grund, warum das Wörterbuch Guss nicht funktioniert, weil IEnumerable Co-Variante ist, beachten Sie <out T> in der Erklärung

public interface IEnumerable<out T> : IEnumerable 

IDictionary ist nicht.

public interface IDictionary<TKey, TValue> : ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable 

Sie können mehr darüber lesen Sie hier: https://msdn.microsoft.com/en-us/library/dd799517(v=vs.110).aspx

Verwandte Themen