C#explicit cast - 从KeyValuerPair的集合到Dictionary

时间:2014-06-19 15:52:34

标签: c#-4.0 .net-4.5

我有一个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 个答案:

答案 0 :(得分:69)

  

意味着我实际上可以将列表转换为字典

嗯,这意味着强制转换在编译时是有效的。这并不意味着它会在执行时工作

可能此代码可以正常工作:

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

...但仅当GetPairs()返回的值是从[{1}}派生的类时,该类也实现了Dictionary<,>。在普通代码中,实际的情况不太可能。编译器不能阻止你尝试,但它不会很好地结束。 (特别是,如果你使用问题中的代码并使用标准的LINQ to Objects执行它,它肯定会在执行时失败。)

你应该坚持使用IOrderedEnumerable<KeyValuePair<string, string>> ......虽然你也应该意识到你将失去顺序,所以没有必要先订购它。

使用您问题中的代码显示此内容:

ToDictionary

编译,但在执行时失败,如预测的那样:

  

未处理的异常:System.InvalidCastException:无法将类型为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.Linq.OrderedEnumerable`2[System.Collections.Generic.KeyValuePair`2[System.Int32,System.String],System.String]'类型。
    在Test.Main()


作为一个背景知识,你可以始终从任何接口类型转换为非密封类(“目标”),即使该类型没有实现接口,因为它是可能的另一个派生自“target”的类来实现接口。

来自C#5规范的第6.2.4节:

  

显式引用转换为:

     
      
  • ...
  •   
  • 从任何类型 'System.Collections.Generic.Dictionary`2[System.Int32,System.String]'到任何接口类型 S,提供的T未被密封并提供{ {1}}未实施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;
    }
}

此时,代码将工作大约一半的时间 - 另一半,它会抛出异常。