Рассмотрим следующую программу:
Код:
namespace DictionaryExploit
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
class Program
{
private static void PrintDictionary(object dictionary)
{
if (dictionary is IDictionary)
{
Console.WriteLine("Dictionary is {0}", dictionary.GetType());
foreach (DictionaryEntry entry in (IDictionary)dictionary)
Console.WriteLine("\t{0} => {1}", entry.Key, entry.Value);
}
else Console.WriteLine("The object of type {0} doesn't implement IDictionary interface.", dictionary.GetType());
}
private static void PrintDictionary(IEnumerable<DictionaryEntry> dictionary)
{
Console.WriteLine("Dictionary represented by {0}", dictionary.GetType());
foreach (var entry in dictionary)
Console.WriteLine("\t{0} => {1}", entry.Key, entry.Value);
}
static void Main(string[] args)
{
try
{
// Non-generic collection: OK, IDictionary is native interface.
PrintDictionary(new Hashtable { { "Key 1", 1 }, { "Key 2", 2 } });
// Generic collection: OK, IDictionary is legacy interface but acts as expected according to LSP.
PrintDictionary(new Dictionary<string, int> { { "Key 1", 1 }, { "Key 2", 2 } });
// LINQ: Typecast transformation of IEnumerable base of legacy IDictionary.
// Expected to act exactly as above, but fails execution with InvalidCastException:
// does attempt conversion from generic KeyValuePair<TKey, TValue> to DictionaryEntry.
PrintDictionary(
((IDictionary)new Dictionary<string, int> { { "Key 1", 1 }, { "Key 2", 2 } })
.Cast<DictionaryEntry>()
);
}
catch (Exception e)
{
Console.WriteLine("Failed with exception: {0}", e.Message);
}
}
}
}
Компиляем, запускаем, видим вот это:
Код:
D:\Projects\DictionaryExploit\bin\Release>DictionaryExploit.exe
Dictionary is System.Collections.Hashtable
Key 1 => 1
Key 2 => 2
Dictionary is System.Collections.Generic.Dictionary`2[System.String,System.Int32]
Key 1 => 1
Key 2 => 2
Dictionary represented by System.Linq.Enumerable+<CastIterator>d__aa`1[System.Collections.DictionaryEntry]
Failed with exception: Specified cast is not valid.
D:\Projects\DictionaryExploit\bin\Release>
Объясните мне пожалуйста, почему так происходит. Я что-то упустил, или это реализация Enumerable.Cast такая?