5

在 C# 中,我发现自己偶尔想在同一事件的调度过程中为某个事件注册一个方法。例如,如果我有一个基于同一事件的连续分派转换状态的类,我可能希望第一个状态的处理程序注销自身并注册第二个处理程序。但是,我不希望在下次触发事件之前调度第二个处理程序。

好消息是,微软的 C# 实现看起来就是这样。事件注册语法糖被替换为对 System.Delegate.Combine 的调用,它只是将当前调用列表和新方法连接到一个单独的列表中,并将其分配给事件属性。这给了我我想要的行为。

所以,我的问题是:这是语言标准保证的行为吗?我希望能够在 mono 下的其他平台上运行我的 C# 代码,并且通常希望确保我不会根据其实现对语言标准做出假设。

我在 MSDN 上找不到任何明确的信息。

如果你想要一个我正在谈论的具体例子,这里有一个例子:

    delegate void TestDelegate();
    static event TestDelegate TestEvent;

    static void Main (string[] args) {
        TestEvent += TestDelegateInstanceFirst;
        TestEvent();
        TestEvent();
    }

    static void TestDelegateInstanceFirst () {
        Console.WriteLine("First");
        TestEvent += TestDelegateInstanceSecond;
    }

    static void TestDelegateInstanceSecond () {
        Console.WriteLine("Second");
    }

至少在 Windows 上,输出是:

First
First
Second
4

1 回答 1

9

是的,这是有保证的。

来自统一的 C# 3.0 规范,第 15.1 节:

但是,当两个非空委托实例组合在一起时,它们的调用列表被连接起来——按照左操作数然后右操作数的顺序——形成一个新的调用列表,其中包含两个或更多条目。

注意“新调用列表”。再次在第 15.3 节中:

一旦实例化,委托实例总是引用相同的目标对象和方法。请记住,当两个委托组合在一起或从另一个委托中删除时,会产生一个新委托,并带有自己的调用列表;合并或删除的委托的调用列表保持不变。

最后,MSDN for System.Delegate 指出:

代表是不可变的;一旦创建,委托的调用列表就不会改变。

我怀疑 CLI 规范中有一些东西 - 我会检查你是否愿意,但希望这三个能给你足够的信心 :)

于 2008-09-26T19:36:29.620 回答