2016-07-18 4 views
19

Sehen Sie im folgenden Code-Schnipsel:Warum schlägt Upcasting IDictionary <TKey, TValue> zu IEnumerable <object> fehl?

(IEnumerable<object>)new Dictionary<string, string>() 

Die obige Besetzung wird eine ungültige Cast Exception werfen.

Tatsächlich IDictionary<TKey, TValue> implementiert auch indirekt IEnumerable<out T>, weil es auch implementiert ICollection<T>. Das heißt, die gesamte Besetzung sollte gültig sein.

In der Tat für mich, es ist noch seltsamer, dass Schlitz sehen, wenn ich die ganze Besetzung auf einem Debugger ausführen, es funktioniert!

Enter image description here

Was ist los?

+1

@PatrickHofman Warum funktioniert es nicht? Es gibt nur eine Schnittstelle namens IEnumerable ', die einen kovarianten Typparameter hat. Auch wenn die Kovarianz nicht mit Werttypen funktioniert ............. Täusche ich mich? –

+0

@CodeCaster Ich meine, dass die Schnittstelle selbst ist IEnumerable ' –

+0

@CodeCaster Argh, https://msdn.microsoft.com/en-us/library/9eekhta0(v=vs.110).aspx –

Antwort

24

Dieses Wörterbuch implementiert IEnumerable<KeyValuePair<TKey, TValue>> und IEnumerable, aber IEnumerable einer Struktur ist nicht identisch mit IEnumerable eines Objekts. Variance only works for reference-types.

Dies funktioniert an meinem Ende und sollte die logische Wahl sein:

var x = (IEnumerable)new Dictionary<string, string>(); 

Als Probe dies funktioniert:

List<string> l = new List<string>(); 
var x = (IEnumerable<object>)l; 

Aber dieses nicht:

List<DateTime> l2 = new List<DateTime>(); 
var x = (IEnumerable<object>)l2; 

Klar, die Struktur ist das Problem.

(Warum es in Merk Fenster funktioniert, weiß ich nicht)

+0

Aber 'IEnumerable ' ist kovariant! –

+0

Und das erklärt nicht, warum eine Uhr mit der gleichen Besetzung bereits funktioniert! –

+0

Weil 'KeyValuePair ' eine Struktur und keine Klasse ist? –

4

Ich denke, das liegt daran, dass KeyValuePair ein Werttyp ist.

Dies würde fehlschlagen:

List<int> ints = new List<int>(); 
var objs = (IEnumerable<object>)ints; 

Dies funktionieren würde:

List<string> ints = new List<string>(); 
var objs = (IEnumerable<object>)ints; 

gleiche gilt für das Wörterbuch.

+0

Du hast absolut recht. Für den Moment sollten wir Patricks Antwort akzeptieren, aber es wäre toll, dass jemand wie Eric Lippert uns antworten könnte, warum der Debugger mehr Macht hat als wir! –

+0

Ich denke, das ist nur ein Parse-Bug in den Debugging-Tools. Ich glaube nicht, dass sie die Aussage wirklich im Handumdrehen zusammenstellen und dann bewerten. @ MatíasFidemraizer –

+1

@PatrickHofman Ja, sollte es sein, dass ... BTW könnte es als Fehler angesehen werden: Debugger mit der tatsächlichen Laufzeitverhalten nicht zu 100% stimmig ist: \ –

0

Das ist seltsam. Ihr Code-Snippet funktioniert gut mit .NET 4.0. Ich schlage vor, dass Sie zu IEnumerable werfen.

lesen: IDictionary Interface (MSDN)

+1

Das ist noch mehr LOL, oder? –

+1

Sind Sie sicher? Ich habe es bereits selbst ausprobiert und es löst die gleiche Ausnahme aus –

+0

Sicher ist, dass es mit .net4.0 funktioniert und mit .net4.5 fehlschlägt. Wie auch immer, Patrick Hofman und user3185569 haben es geschafft. Aus der MSDN, es implementiert IEnumerable >, NICHT IEnumerable , da KeyValuePair eine Struktur ist. Ich schlage vor, wir akzeptieren Patrick Hofmans Antwort –

1

Wenn Sie wirklich nicht mit einfachen IEnumerable leben können, versuchen Sie dies:

new Dictionary<string, string>().Cast<object>(); 
+0

Das ist nicht die Frage. OP weiß das sicher. Er will nur wissen, warum das passiert. –

+0

Ja, absolut. Das Problem ist Aufruf 'Enumerable.Cast' produziert eine ** neue Enumerable ** und ich muss die gleiche Instanz halten und es einfach auf verschiedene Schnittstellen umwandeln, die durch den ganzen Typ –

+0

implementiert werden Können Sie Unterklasse 'Dictionary '? Wenn Sie können, können Sie es implementieren IEnumerable . –

Verwandte Themen