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

Bop*_*Bop 10 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;
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 69

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

好吧,这意味着演员阵容在编译时是有效的.这并不意味着它将在执行时工作.

这是可能的,这个代码可以工作:

IOrderedEnumerable<KeyValuePair<string, string>> pairs = GetPairs();
Dictionary<string, string> dictionary = (Dictionary<string, string>) pairs;
Run Code Online (Sandbox Code Playgroud)

...但仅当返回的值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;
Run Code Online (Sandbox Code Playgroud)

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

未处理的异常: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()


作为一个背景,你总是可以从任何接口类型转换为非密封类("目标"),即使该类型没有实现接口,因为从"目标"派生的另一个类可以实现界面.

从C#5规范的6.2.4节:

显式引用转换是:

  • ...
  • 从任何类类型 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

错误信息:

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

所以我们可以添加一个演员:

IFormattable x = (IFormattable) GetObject();
Run Code Online (Sandbox Code Playgroud)

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

  • @BoppityBop:看看我的答案中的代码,它与你的代码相同,但包括一个演员.编译,但会在执行时失败.不同之处在于你试图*隐式*将`s`的值转换为`Dictionary <int,string>`,而我的代码使用强制转换使代码*显式*. (2认同)
  • @BoppityBop:你提供的代码显示了一个隐式转换的尝试,因为它试图将类型为`IOrderedEnumerable <KeyValuePair <string,int >>`的值赋给`Dictionary <string,int>`类型的变量.如果您在实际代码中遇到错误,我怀疑您正在做类似的事情.我的回答表明它可以在编译时,但它会在执行时失败. (2认同)