Untuk menjawab pertanyaan Anda:
- Memunculkan acara memang memblokir utas jika semua penangan acara diterapkan secara sinkron.
- Penangan acara dijalankan secara berurutan, satu demi satu, dalam urutan mereka berlangganan acara tersebut.
Saya juga ingin tahu tentang mekanisme internal event
dan operasinya yang terkait. Jadi saya menulis program sederhana dan terbiasa ildasm
melihat-lihat implementasinya.
Jawaban singkatnya adalah
- tidak ada operasi asinkron yang terlibat dalam berlangganan atau menjalankan acara.
- acara diimplementasikan dengan bidang delegasi dukungan dari jenis delegasi yang sama
- berlangganan selesai dengan
Delegate.Combine()
- berhenti berlangganan selesai dengan
Delegate.Remove()
- Pemanggilan dilakukan dengan hanya memanggil delegasi gabungan terakhir
Inilah yang saya lakukan. Program yang saya gunakan:
public class Foo
{
// cool, it can return a value! which value it returns if there're multiple
// subscribers? answer (by trying): the last subscriber.
public event Func<int, string> OnCall;
private int val = 1;
public void Do()
{
if (OnCall != null)
{
var res = OnCall(val++);
Console.WriteLine($"publisher got back a {res}");
}
}
}
public class Program
{
static void Main(string[] args)
{
var foo = new Foo();
foo.OnCall += i =>
{
Console.WriteLine($"sub2: I've got a {i}");
return "sub2";
};
foo.OnCall += i =>
{
Console.WriteLine($"sub1: I've got a {i}");
return "sub1";
};
foo.Do();
foo.Do();
}
}
Berikut implementasi Foo:
Perhatikan bahwa ada lapangan OnCall
dan acara OnCall
. Lapangan OnCall
jelas merupakan properti pendukung. Dan itu hanya Func<int, string>
, tidak ada yang mewah di sini.
Sekarang bagian yang menarik adalah:
add_OnCall(Func<int, string>)
remove_OnCall(Func<int, string>)
- dan bagaimana
OnCall
dipanggilDo()
Bagaimana Berlangganan dan Berhenti Berlangganan Diterapkan?
Berikut add_OnCall
implementasi yang disingkat di CIL. Bagian yang menarik adalah digunakan Delegate.Combine
untuk menggabungkan dua delegasi.
.method public hidebysig specialname instance void
add_OnCall(class [mscorlib]System.Func`2<int32,string> 'value') cil managed
{
// ...
.locals init (class [mscorlib]System.Func`2<int32,string> V_0,
class [mscorlib]System.Func`2<int32,string> V_1,
class [mscorlib]System.Func`2<int32,string> V_2)
IL_0000: ldarg.0
IL_0001: ldfld class [mscorlib]System.Func`2<int32,string> ConsoleApp1.Foo::OnCall
// ...
IL_000b: call class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate,
class [mscorlib]System.Delegate)
// ...
} // end of method Foo::add_OnCall
Demikian juga, Delegate.Remove
digunakan dalam remove_OnCall
.
Bagaimana sebuah acara dipanggil?
Untuk memanggil OnCall
di Do()
, itu hanya menyebut delegasi bersambung final setelah memuat arg yang:
IL_0026: callvirt instance !1 class [mscorlib]System.Func`2<int32,string>::Invoke(!0)
Bagaimana tepatnya pelanggan berlangganan suatu acara?
Dan akhirnya, Main
tidak mengherankan, berlangganan ke OnCall
acara dilakukan dengan memanggil add_OnCall
metode pada Foo
instance.