'委托'System.Action'不需要0个参数。' 这是一个C#编译器错误(lambdas +两个项目)?

考虑下面的代码。 看起来像完全有效的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 }; } } 

我得到一个编译器错误'委托'行动'不接受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 */ }; } } 

我偶然发现了一个C#编译器错误吗?

请注意,这是一个非常喜欢使用lambdas的人很多恼人的错误,正在尝试创build一个数据结构库以供将来使用…(me)

编辑:删除了错误的情况。

我复制并剥离了我的原始项目到最低限度,以实现这一目标。 这实际上是我的新项目中的所有代码。

这可能是types排除的一个问题,编译器推断a Action<T>而不是Action (它可能认为是ActionSurrogate ,它将适合Action<Action>>签名)。 尝试指定明确的types:

  ActionSurrogate b = (Action a) => { a(); }; 

如果情况并非如此 – 可能会检查您的项目中是否有任何自定义的Action代表接受一个参数。

最终更新:

这个错误已经在C#5中修复了。再次为这个不便之处再次道歉,谢谢你的报告。


原始分析:

我可以重现与命令行编译器的问题。 它看起来像一个错误。 这可能是我的错; 对于那个很抱歉。 (我写了所有的lambda-to-delegate转换检查代码。)

我现在正在咖啡店里,而且我没有从这里访问编译器源代码。 我会尽量find一些时间在明天的debugging版本中重现这个问题,看看能不能解决这个问题。 如果我找不到时间,我会在圣诞节之后不在办公室。

你的观察,引入一个variablestypes的行动导致问题消失是非常有趣的。 编译器为了性能原因和语言规范所要求的分析而维护许多高速caching。 特别是Lambda和局部variables有很多复杂的caching逻辑。 我愿意下注多达一美元,一些caching被初始化或填充错误,并且使用本地variables填充caching中的正确值。

感谢您的报告!

更新:我现在在公共汽车上,它只是对我来说; 我想我确切地知道什么是错的。 编译器是懒惰的 ,特别是在处理来自元数据的types时。 原因是在引用的程序集中可能有成千上万个types,并且不需要加载关于它们的所有信息。 你可能使用的远远不到其中的1%,所以我们不要浪费大量时间和内存来加载你永远不会使用的东西。 事实上,懒惰比这更深。 一个types可以通过几个“阶段”才可以使用。 首先它的名字是已知的,然后是它的基types,然后是它的基types层次结构是否是有根据的(非循环等),然后是它的types参数约束,然后是它的成员,然后成员是否有充分的根据相同的签名,等等)。我敢打赌,转换逻辑没有调用“确保所有委托参数的types有成员已知”的方法,在它检查委托的签名之前调用兼容性。 但是,使本地variables的代码可能做到这一点。 我认为,在转换检查期间,就编译器而言,Actiontypes可能甚至没有调用方法。

我们马上就会知道

更新:我的精神力量今天早晨强大。 如果重载决策尝试确定是否存在采用零参数的委托types的“调用”方法,则会find可供select的零调用方法 。 在重载parsing之前,我们应该确保委托types元数据已经完全加载。 这已经被忽视了多久, 它在C#3.0中重现。 当然,C#2.0中并没有重新生成,因为没有lambdaexpression式。 C#2.0中的匿名方法要求你显式地声明types,这会创build一个本地的,我们知道加载元数据。 但我可以想象,错误的根源 – 重载parsing不会强制为调用加载元数据 – 可以回到C#1.0。

无论如何,迷人的错误,感谢报告。 显然你有一个解决方法。 我将从此处跟踪QA,我们将尝试修复C#5(我们已经错过了Service Pack 1的窗口,这个窗口已经在testing版了 。)

  public static void ThisWontCompile() { ActionSurrogate b = (Action a) => { a(); }; } 

这将编译。 一些小故障与编译器无法find没有参数的操作委托。 这就是为什么你得到错误。

 public delegate void Action(); public delegate void Action<T>(); public delegate void Action<T1,T2>(); public delegate void Action<T1,T2,T3>(); public delegate void Action<T1,T2,T3,T4>();