С# явное приведение - из коллекции KeyValuerPair в словарь

У меня есть список KeyValuePairs. Я обычно использовал бы ToDictionary.

Однако я только отметил, что сообщение об ошибке (показано ниже) имеет что-то о явном приведении в действие, что означает, что я могу фактически перечислить список Dictionary<...>. Как я могу это сделать?

Cannot implicitly convert type 'System.Linq.IOrderedEnumerable<System.Collections.Generic.KeyValuePair<int,string>>' to 'System.Collections.Generic.Dictionary<int, string>'. An explicit conversion exists (are you missing a cast?)

Пример кода:

Dictionary<int, string> d = new Dictionary<int, string>() { 
    {3, "C"},
    {2, "B"},
    {1, "A"},
};

var s = d.OrderBy(i => i.Value);

d = s;

Ответ 1

Предполагается, что я могу фактически перечислить список в словарь

Ну, это означает, что приведение будет действительным во время компиляции. Это не значит, что он будет работать во время выполнения.

Возможно, этот код мог бы работать:

IOrderedEnumerable<KeyValuePair<string, string>> pairs = GetPairs();
Dictionary<string, string> dictionary = (Dictionary<string, string>) pairs;

... но только если значение, возвращаемое GetPairs(), было классом, полученным из Dictionary<,>, который также реализовал IOrderedEnumerable<KeyValuePair<string, string>>. Это очень маловероятно, что на самом деле это дело в нормальном коде. Компилятор не может помешать вам попробовать, но это не закончится хорошо. (В частности, если вы сделаете это с кодом в своем вопросе и со стандартным LINQ to Objects, он, безусловно, завершится неудачно во время выполнения.)

Вы должны придерживаться ToDictionary... хотя вы также должны знать, что вы потеряете порядок, поэтому нет смысла его начинать с.

Чтобы показать это с кодом в своем вопросе:

Dictionary<int, string> d = new Dictionary<int, string>() { 
    {3, "C"},
    {2, "B"},
    {1, "A"},
};

var s = d.OrderBy(i => i.Value);

d = (Dictionary<int, string>) s;

Это компилируется, но не выполняется во время выполнения, как и прогнозировалось:

Необработанное исключение: System.InvalidCastException: Невозможно применить объект типа 'System.Linq.OrderedEnumerable`2[System.Collections.Generic.KeyValuePair`2[System.Int32,System.String],System.String]' к типу 'System.Collections.Generic.Dictionary`2[System.Int32,System.String]'.
  на Test.Main()


Как немного фона, вы всегда можете использовать любой тип интерфейса для непечатаемого класса ( "target" ), даже если этот тип не реализует интерфейс, потому что он возможен для другого класса, полученного из "target" "для реализации интерфейса.

Из раздела 6.2.4 спецификации С# 5:

Явные ссылочные преобразования:

  • ...
  • От любого типа класса S до любого типа интерфейса T при условии, что S не запечатан и при условии, что S не реализует T.
  • ...

(Случай, когда S реализует T, покрывается неявными ссылочными преобразованиями.)

Если вы попытаетесь неявно преобразовать значение и нет доступного имплицированного доступа, но есть явное преобразование, компилятор даст вам предупреждение в вашем вопросе. Это означает, что вы можете исправить ошибку компилятора с помощью трансляции, но вам нужно знать о возможности ее отказа во время выполнения.

Вот пример:

using System;

class Test
{
    static void Main()
    {
        IFormattable x = GetObject();
    }

    static object GetObject()
    {
        return DateTime.Now.Second >= 30 ? new object() : 100;
    }
}

Сообщение об ошибке:

Test.cs(7,26): error CS0266: Cannot implicitly convert type 'object' to 
   'System.IFormattable'. An explicit conversion exists (are you missing a cast?)

Итак, мы можем добавить актерский состав:

IFormattable x = (IFormattable) GetObject();

В этот момент код будет работать примерно в половине случаев - в другой половине, это вызовет исключение.