Open2

C# のイベントはイベントハンドラーを同期的に呼ぶか?(答え:呼ぶ)

たいぷらいた~たいぷらいた~

実験

実行環境: .NET 6.0, .NET 7.0 両方 (Windows 11 22H2)

同期版

Program.cs
var sampleClass = new SampleClass();
sampleClass.SampleEvent += (s, e) => { Console.WriteLine("{0}: Handler 1 called.", DateTime.Now); Thread.Sleep(1000); };
sampleClass.SampleEvent += (s, e) => { Console.WriteLine("{0}: Handler 2 called.", DateTime.Now); Thread.Sleep(1000); };
sampleClass.SampleEvent += (s, e) => { Console.WriteLine("{0}: Handler 3 called.", DateTime.Now); Thread.Sleep(1000); };
sampleClass.RaiseEvent();

public class SampleClass
{
    public event EventHandler SampleEvent = (s,e) => { };
    public void RaiseEvent() { SampleEvent(this, EventArgs.Empty); }
}
実行結果
2023/08/13 23:13:00: Handler 1 called.
2023/08/13 23:13:01: Handler 2 called.
2023/08/13 23:13:02: Handler 3 called.

非同期版

Program.cs
var sampleClass = new SampleClass();
sampleClass.SampleEvent += async (s, e) => { Console.WriteLine("{0}: Handler 1 called.", DateTime.Now); await Task.Delay(1000); };
sampleClass.SampleEvent += async (s, e) => { Console.WriteLine("{0}: Handler 2 called.", DateTime.Now); await Task.Delay(1000); };
sampleClass.SampleEvent += async (s, e) => { Console.WriteLine("{0}: Handler 3 called.", DateTime.Now); await Task.Delay(1000); };
sampleClass.RaiseEvent();

public class SampleClass
{
    public event EventHandler SampleEvent = (s,e) => { };
    public void RaiseEvent() { SampleEvent(this, EventArgs.Empty); }
}
実行結果
2023/08/13 23:14:06: Handler 1 called.
2023/08/13 23:14:06: Handler 2 called.
2023/08/13 23:14:06: Handler 3 called.

実験結果

  • イベントにサブスクライブした順で、同期的に実行される。
  • async キーワードで非同期メソッドにすると、非同期で実行される。
たいぷらいた~たいぷらいた~

ドキュメント

  • イベントはデリゲートを用いて実現されている?
  • Delegate, MulticastDelegate ともに、呼び出しリストの順に実行する旨の記述がある。 MulticastDelegate には、同期的に実行するとの記述もある。

デリゲートはマルチキャストです。つまり、複数のイベント処理メソッドへの参照を保持できます。 詳細については、Delegate のリファレンス ページを参照してください。

イベントの処理と発生 | Microsoft Learn

A MulticastDelegate has a linked list of delegates, called an invocation list, consisting of one or more elements. When a multicast delegate is invoked, the delegates in the invocation list are called synchronously in the order in which they appear.

MulticastDelegate Class (System) | Microsoft Learn

The invocation list of a delegate is an ordered set of delegates in which each element of the list invokes exactly one of the methods represented by the delegate. An invocation list can contain duplicate methods. During an invocation, methods are invoked in the order in which they appear in the invocation list.

Delegate Class (System) | Microsoft Learn