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.
Ini adalah jawaban umum dan mencerminkan perilaku default:
Karena itu, setiap kelas yang menyediakan event dapat memilih untuk mengimplementasikan eventnya secara asynchronous. IDesign menyediakan kelas yang disebut
EventsHelper
yang menyederhanakan ini.[Note] tautan ini mengharuskan Anda memberikan alamat email untuk mengunduh kelas EventsHelper. (Saya tidak berafiliasi dengan cara apa pun)
sumber
Delegasi yang berlangganan acara dipanggil secara sinkron sesuai urutan penambahannya. Jika salah satu delegasi melontarkan pengecualian, yang berikut ini tidak akan dipanggil.
Karena peristiwa ditentukan dengan delegasi multicast, Anda dapat menulis mekanisme pengaktifan Anda sendiri menggunakan
dan memanggil delegasi secara asynchronous;
sumber
Acara hanyalah susunan delegasi. Selama panggilan delegasi sinkron, acara juga akan sinkron.
sumber
Secara umum, peristiwa bersifat sinkron. Namun ada beberapa pengecualian, seperti
System.Timers.Timer.Elapsed
peristiwa yang dimunculkan diThreadPool
thread jikaSyncronisingObject
null.Docs: http://msdn.microsoft.com/en-us/library/system.timers.timer.elapsed.aspx
sumber
Acara di C # berjalan serentak (dalam kedua kasus), selama Anda tidak memulai utas kedua secara manual.
sumber
Acara bersifat sinkron. Inilah sebabnya mengapa siklus hidup acara bekerja seperti itu. Init terjadi sebelum pemuatan, pemuatan terjadi sebelum render, dll.
Jika tidak ada penangan yang ditentukan untuk sebuah acara, siklus akan langsung menyala. Jika lebih dari satu penangan ditentukan, mereka akan dipanggil secara berurutan dan salah satu tidak dapat melanjutkan sampai penangan lainnya selesai sepenuhnya.
Bahkan panggilan asinkron pun sinkron sampai tingkat tertentu. Tidak mungkin untuk memanggil akhir sebelum permulaan selesai.
sumber