“委托” system.Action'不需要0参数。这是C#编译器错误(Lambdas +两个项目)吗?

StackOverflow https://stackoverflow.com/questions/4466859

考虑以下代码。看起来完全有效的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编译器。请注意,您必须在另一个项目中声明ActionRogate才能表现出此错误。

它变得更加有趣:

// 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的人来说,这是一个非常烦人的错误,并试图创建一个数据结构库以备将来使用...

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

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

有帮助吗?

解决方案

这可能是推断类型的问题 a 作为一个 Action<T> 代替 Action (可能认为 aActionSurrogate, ,这适合 Action<Action>> 签名)。尝试指定类型 a 明确:

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

如果不是这种情况 - 可能会检查您的项目是否有任何自定义 Action 代表采用一个参数。

其他提示

最终更新:

该错误已在C#5中解决。


原始分析:

我可以用命令行编译器复制问题。当然看起来像个错误。这可能是我的错;对于那个很抱歉。 (我写了所有的lambda到二级转换检查代码。)

我现在在一家咖啡店里,我无法从这里访问编译器来源。我将尝试一些时间在明天的调试构建中重现这一点,看看我是否可以弄清楚发生了什么。如果我找不到时间,我会直到圣诞节过后就离开办公室。

您对引入类型动作变量的观察结果导致问题消失非常有趣。由于表现原因和语言规范所需的分析,编译器维护许多缓存。 Lambdas和本地变量特别具有许多复杂的缓存逻辑。我愿意下注一美元,在此处进行一些缓存的初始化或填充错误,并且使用本地变量的使用填充了缓存中的正确值。

感谢您的报告!

更新:我现在在公共汽车上,只是来找我。我想我确切知道怎么了。编译器是 懒惰的, ,特别是在处理来自元数据的类型时。原因是参考组件中可能有数十万类型,并且无需加载有关所有信息的信息。您可能会使用少于1%的使用,因此,我们不要浪费很多时间和内存加载的东西。实际上,懒惰比这更深。一种类型在使用之前通过几个“阶段”。首先,它的名称是已知的,然后是基本类型,然后是其基本类型层次结构是否有良好的基础类型(循环等),然后是其类型的参数约束,然后是其成员,然后成员是否有良好的基础(覆盖覆盖层覆盖某些东西相同的签名等等。)我敢打赌,转换逻辑未能调用说“确保所有委托参数的类型 他们的 成员已知“”,在检查委托签名的签名之前 去做。我认为,在转换检查中,就编译器而言,动作类型甚至可能没有一种调用方法。

我们很快会发现。

更新:我的心理力量今天早上很强。当过载分辨率试图确定是否有零参数的委托类型的“调用”方法时,它找到了 零调用方法可供选择. 。我们应该确保在进行过载分辨率之前,将委托类型元数据充分加载。这么长时间没有注意到这一点多么奇怪。它在C#3.0中reprolos。当然,它不会仅仅因为没有lambdas而在C#2.0中复制。 C#2.0中的匿名方法要求您明确陈述类型,该类型会创建局部,我们知道它加载了元数据。但是我想,该错误的根本原因 - 超载分辨率不会强迫加载元数据作为调用 - 返回到C#1.0。

无论如何,令人着迷的错误,感谢您的报告。显然,您有解决方法。我将从这里从这里进行QA跟踪,我们将尝试将其修复为C#5。(我们错过了窗口 服务包1,已经在beta中.)

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


        }

这将编译。一些与编译器的小故障无法在没有参数的情况下找到动作委托。这就是为什么您会遇到错误。

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>();
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top