Dan*_*rth 70
这是一般性答案,反映了默认行为:
话虽如此,提供事件的每个类都可以选择异步实现其事件.IDesign提供了一个称为EventsHelper简化此类的类.
[注意]此链接要求您提供下载EventsHelper类的电子邮件地址.(我不以任何方式加入)
KFL*_*KFL 27
回答你的问题:
我也对其内部机制event及其相关操作感到好奇.所以我写了一个简单的程序,并习惯于ildasm围绕它的实现.
简短的回答是
Delegate.Combine()Delegate.Remove()这就是我做的.我用过的程序:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
这是Foo的实现:
请注意,有一个字段 OnCall和一个事件 OnCall.该领域OnCall显然是支持财产.它只是一个Func<int, string>,没有什么花哨的.
现在有趣的部分是:
add_OnCall(Func<int, string>)remove_OnCall(Func<int, string>)OnCall调用Do()这是add_OnCallCIL中的缩写实现.有趣的是它用于Delegate.Combine连接两个委托.
.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
Run Code Online (Sandbox Code Playgroud)
同样,Delegate.Remove用于remove_OnCall.
要调用OnCall的Do(),它只是加载ARG后调用最终级联委托:
IL_0026: callvirt instance !1 class [mscorlib]System.Func`2<int32,string>::Invoke(!0)
Run Code Online (Sandbox Code Playgroud)
最后,Main并非OnCall令人惊讶的是,通过调用实例add_OnCall上的方法来订阅事件Foo.
Vla*_*mir 14
订阅该事件的代理按照添加顺序同步调用.如果其中一个委托抛出异常,则不会调用以下代理.
由于事件是使用多播委托定义的,因此您可以使用编写自己的触发机制
Delegate.GetInvocationList();
Run Code Online (Sandbox Code Playgroud)
并异步调用委托;
通常,事件是同步的.但是有一些例外,例如如果为null 则System.Timers.Timer.Elapsed在ThreadPool线程上引发事件SyncronisingObject.
文档:http://msdn.microsoft.com/en-us/library/system.timers.timer.elapsed.aspx