为什么c#编译器在这段代码上崩溃了?

本文关键字:代码 崩溃 编译器 段代码 为什么 | 更新日期: 2023-09-27 18:09:36

为什么下面的代码会使。net编译器崩溃?在csc.exe 4.0版本上进行了测试。

参见这里不同版本的在线演示-它以同样的方式崩溃,同时它说不支持动态https://dotnetfiddle.net/FMn59S:

编译错误(第0行,col 0):内部编译错误(0xc0000005 at address xy):可能的罪魁祸首是'TRANSFORM'.

扩展方法在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的,但似乎编译器在应用于从Dictionary<T1,T2>派生的类的任何扩展方法时都会崩溃,其中至少有一个参数类型是dynamic。请看下面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));

为什么c#编译器在这段代码上崩溃了?

动态触发不稳定性,当你用对象替换它时崩溃消失。

这是一个解决方法,另一个是帮助它推断正确的T:

static void U(C.K d) {
    d.M(new Action<KeyValuePair<string, dynamic>>(kvp => Console.WriteLine(kvp)));
}

你找到的反馈报告是一个强有力的匹配,我认为没有必要提交你自己的。

好吧,你的问题的答案,为什么它崩溃编译器,这是因为你遇到了一个bug ....编译器崩溃。

VS2013编译器说"内部编译器错误(0xc0000005在地址012DC5B5):可能的罪魁祸首是'TRANSFORM'",所以很明显这是一个错误。

C0000005通常是一个空指针,或引用未分配或已删除的内存。这是一般的保护故障。

编辑:

这个问题也存在于几乎任何类型的多参数泛型类型中,其中任意参数是动态的。例如:

List<Tuple<string, dynamic>>{}

也会在

上崩溃
List<KeyValuePair<dynamic, string>>{}

但不崩溃

List<dynamic>{}

但是在

上崩溃
List<List<dynamic>>{}