2016-07-21 7 views
2

Я узнал, что HashSet реализует интерфейс IEnumerable. Таким образом, можно неявно отбрасывать HashSet объект в IEnumerable:Преобразование типа C#: Явное литье существует, но выдает ошибку преобразования?

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

Это работает для вложенных универсальных типов, тоже:

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

По крайней мере, это то, что я думал. Но если я сделаю Dictionary, я столкнулся с проблемой:

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

Последняя строка дает мне следующую ошибку компиляции (Visual Studio 2015):

Не может неявно преобразовать тип

System.Collections.Generic.IDictionary<T, System.Collections.Generic.HashSet<T>> до System.Collections.Generic.IDictionary<T, System.Collections.Generic.IEnumerable<T>>.

Явное преобразование существует (вы пропали без вести броска?)

Но если я бросание написав

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

тогда я получаю недопустимое исключение во время выполнения броска.

Два вопроса:

  • Как решить эту проблему? Является единственным способом перебора ключей и создания нового словаря по-разному?
  • Зачем мне эта проблема в первую очередь, хотя HashSet действительно реализует интерфейс IEnumerable?
+0

'' IEnumerable является [ковариантный] (https://msdn.microsoft.com/en-gb/library/mt654060.aspx). 'IDictionary ' нет. Это * внешние * типы, где это важно –

ответ

5

Причина, по которой не работает, что значение в IDictionary<TKey, TValue> не co-variant (и ни ключ, по тем же причинам).Если бы это было разрешено быть, то этот код будет компилироваться, но имеет привести к исключению:

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

Можно подумать, что добавление List<T> будет работать, так как он обобщит данный тип значения, предположительно IEnumerable<T>. Однако это не может быть успешным, поскольку значение действительного значения составляет HashSet<T>.

Итак, да: единственный способ - создать новый словарь.

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

Как это решить? Единственный способ перебирать ключи и создать бит-бит по-новому?

Это может быть не самым элегантным решением, но оно работает:

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); 

Причина словарь литой не работают потому, что IEnumerable является одним из вариантов, обратите внимание <out T> в декларации

public interface IEnumerable<out T> : IEnumerable 

IDictionary нет.

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

Вы можете прочитать об этом здесь: https://msdn.microsoft.com/en-us/library/dd799517(v=vs.110).aspx

Смежные вопросы