Sorularınızı cevaplamak için:
- Olay işleyicilerinin tümü eşzamanlı olarak uygulanıyorsa, bir olayın başlatılması iş parçacığını engeller.
- Olay işleyicileri, olaya abone oldukları sırada birbiri ardına yürütülür.
Ben de iç mekanizması event
ve bununla ilgili işlemleri merak ediyordum . Bu yüzden basit bir program yazdım ildasm
ve uygulanmasının etrafından dolaşıyordum.
Kısa cevap
- olaylara abone olma veya olayları çağırma ile ilgili hiçbir zaman uyumsuz işlem yoktur.
- olay, aynı delege türündeki bir destek delege alanıyla uygulanır
- abone olmak ile yapılır
Delegate.Combine()
- abonelik iptali ile yapılır
Delegate.Remove()
- Çağırma, yalnızca son birleşik delegeyi çağırarak yapılır.
İşte yaptığım şey. Kullandığım program:
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();
}
}
İşte Foo'nun uygulaması:
Bir alan OnCall
ve bir olay olduğunu unutmayın OnCall
. Alan OnCall
, kesinlikle destekleyici mülktür. Ve bu sadece bir Func<int, string>
, burada süslü değil.
Şimdi ilginç kısımlar:
add_OnCall(Func<int, string>)
remove_OnCall(Func<int, string>)
- ve nasıl
OnCall
çağrılırDo()
Abone Olma ve Aboneliği İptal Etme Nasıl Uygulanır?
İşte add_OnCall
CIL'deki kısaltılmış uygulama. İlginç olan kısım, Delegate.Combine
iki delegeyi birleştirmek için kullanmasıdır .
.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
Aynı şekilde Delegate.Remove
kullanılır remove_OnCall
.
Bir olay nasıl başlatılır?
Çağırmak OnCall
için Do()
, arg'yi yükledikten sonra son birleştirilmiş temsilciyi çağırır:
IL_0026: callvirt instance !1 class [mscorlib]System.Func`2<int32,string>::Invoke(!0)
Bir abone bir etkinliğe tam olarak nasıl abone olur?
Ve son olarak, Main
şaşırtıcı bir şekilde, OnCall
olaya abone olmak add_OnCall
, Foo
örnek üzerinde yöntem çağırarak yapılır .