Ale*_*ink 42 c# lambda compiler-errors compiler-bug
请考虑以下代码.看起来完全有效的C#代码对吗?
//Project B
using System;
public delegate void ActionSurrogate(Action addEvent);
//public delegate void ActionSurrogate2();
// Using ActionSurrogate2 instead of System.Action results in the same error
// Using a dummy parameter (Action<double, int>) results in the same error
// Project A
public static class Class1 {
public static void ThisWontCompile() {
ActionSurrogate b = (a) =>
{
a(); // Error given here
};
}
}
Run Code Online (Sandbox Code Playgroud)
我得到一个编译错误'委托'动作'不接受0参数.使用(Microsoft)C#4.0编译器在指定位置.请注意,您必须在另一个项目中声明ActionSurrogate才能显示此错误.
它变得更有趣:
// Project A, File 1
public static class Class1 {
public static void ThisWontCompile() {
ActionSurrogate b = (a) => { a(); /* Error given here */ };
ActionSurrogate c = (a) => { a(); /* Error given here too */ };
Action d = () => { };
ActionSurrogate c = (a) => { a(); /* No error is given here */ };
}
}
Run Code Online (Sandbox Code Playgroud)
我偶然发现了一个C#编译器错误吗?
请注意,对于喜欢使用lambdas并尝试创建数据结构库以供将来使用的人来说,这是一个非常烦人的错误...(我)
编辑:删除了错误的案例.
我将原始项目复制并删除到最低限度以实现此目的.这实际上是我新项目中的所有代码.
Eri*_*ert 67
该错误已在C#5中修复.再次为此带来不便,并感谢报告.
我可以使用命令行编译器重现该问题.它当然看起来像一个bug.这可能是我的错; 对于那个很抱歉.(我写了所有lambda-to-delegate转换检查代码.)
我现在在咖啡店,我无法从这里访问编译器源.我将试着找一些时间在明天的调试版本中重现这一点,看看我是否可以解决正在发生的事情.如果我没有找到时间,我会在圣诞节之后离开办公室.
您对引入Action类型变量导致问题消失的观察非常有趣.编译器为性能原因和语言规范所需的分析维护了许多高速缓存.Lambda和局部变量尤其具有许多复杂的缓存逻辑.我愿意打赌一些缓存正在初始化或填写错误的一美元,并且使用局部变量填充缓存中的正确值.
谢谢你的报道!
更新:我现在在公共汽车上,它刚刚来到我身边; 我想我确切地知道出了什么问题.编译器很懒惰,特别是在处理来自元数据的类型时.原因是引用的程序集中可能有数十万种类型,并且不需要加载有关所有类型的信息.你可能会使用它们中不到1%,所以不要浪费大量时间和内存加载你永远不会使用的东西.事实上,懒惰比这更深刻; 一种类型在可以使用之前经过几个"阶段".首先它的名称是已知的,然后是它的基本类型,然后它的基本类型层次结构是否有充分根据(非循环等),然后是它的类型参数约束,然后是它的成员,然后是成员是否有充分根据(覆盖覆盖某些东西)相同的签名,等等.)我敢打赌转换逻辑无法调用"确保所有委托参数的类型已知其成员"的方法,然后才检查委托的签名调用兼容性.但是,使一个局部变量可能的代码确实做到这一点.我认为在转换检查期间,就编译器而言,Action类型可能甚至没有调用方法.
我们很快就会发现.
更新:今天早上我的精神力量很强.当重载决策尝试确定是否存在带有零参数的委托类型的"Invoke"方法时,它会找到零Invoke方法以供选择.我们应该确保在进行重载解析之前完全加载委托类型元数据.多久没有注意到这一点有多奇怪; 它在C#3.0中的重复.当然,它不会仅仅因为没有lambda而在C#2.0中重现; C#2.0中的匿名方法要求您明确声明类型,这会创建一个本地,我们知道加载元数据.但我认为错误的根本原因 - 重载解析不会强制加载调用的元数据 - 返回到C#1.0.
无论如何,迷人的bug,感谢报告.显然你有一个解决方法.我将从这里进行QA跟踪,我们将尝试为C#5修复它.(我们已经错过了Service Pack 1的窗口,它已经处于测试阶段.)
Fem*_*ref 23
这可能是与类型inferance问题,apperently编译器推断a为Action<T>,而不是Action(这可能会认为a是ActionSurrogate,这将符合Action<Action>>签名).尝试明确指定类型a:
ActionSurrogate b = (Action a) =>
{
a();
};
Run Code Online (Sandbox Code Playgroud)
如果不是这种情况 - 可以检查项目周围是否有任何自定义Action代理采用一个参数.