【发布时间】:2014-08-12 06:30:30
【问题描述】:
为什么下面的代码会使 .NET 编译器崩溃?在 csc.exe 4.0 版上测试过。
参见例如这里是不同版本的在线演示 - 它以相同的方式崩溃,同时它说不支持动态https://dotnetfiddle.net/FMn59S:
编译错误(第 0 行,第 0 列):内部编译器错误(地址 xy 处的 0xc0000005):可能的罪魁祸首是“转换”。
扩展方法在List<dynamic> 上运行良好。
using System;
using System.Collections.Generic;
static class F {
public static void M<T>(this IEnumerable<T> enumeration, Action<T> action){}
static void U(C.K d) {
d.M(kvp => Console.WriteLine(kvp));
}
}
class C {
public class K : Dictionary<string, dynamic>{}
}
更新:这不会使编译器崩溃
static void U(Dictionary<string, dynamic> d)
{
d.M(kvp => Console.WriteLine(kvp));
}
更新 2:http://connect.microsoft.com/VisualStudio/feedback/details/892372/compiler-error-with-dynamic-dictinoaries 中报告了相同的错误。该错误是针对 FirstOrDefault 报告的,但似乎编译器在应用于从 Dictionarydynamic。请参阅 Erik Funkenbusch 对以下问题的更一般性描述。
更新 3:另一个非标准行为。当我尝试将扩展方法作为静态方法调用时,即F.M(d, kvp => Console.WriteLine(kvp));,编译器不会崩溃,但找不到重载:
Argument 1: cannot convert from 'C.K' to 'System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string,dynamic>>'
更新 4 - 解决方案(种类):Hans 勾勒出第二种解决方法,它在语义上等同于原始代码,但仅适用于扩展方法调用,不适用于标准调用。由于该错误很可能是由于编译器无法将具有多个参数(其中一个是动态的)的泛型类派生的类转换为其超类型,因此解决方案是提供显式转换。见https://dotnetfiddle.net/oNvlcL:
((Dictionary<string, dynamic>)d).M(kvp => Console.WriteLine(kvp));
M((Dictionary<string, dynamic>)d, kvp => Console.WriteLine(kvp));
【问题讨论】:
-
类名的好选择。
-
FWIW,罗斯林编译了这个。
-
@Henk Holterman 看来这个bug是一样的——FirstOrDefault也是扩展方法connect.microsoft.com/VisualStudio/feedback/details/892372/…
-
我很难弄清楚什么答案会真正回答“为什么我没有源代码的程序会崩溃?”这个问题?您打算从这个问题的任何答案中学到什么?
-
@Eric - 我希望了解一些关于编译器内部工作原理的知识,并找出这个错误的实际程度,因为它出现的情况比我最初想象的要多。