Answers:
要回答您的问题:
我也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();
}
}
这是Foo的实现:
请注意,有一个字段 OnCall
和一个事件 OnCall
。该字段OnCall
显然是支持属性。它只是一个Func<int, string>
,在这里没有幻想。
现在有趣的部分是:
add_OnCall(Func<int, string>)
remove_OnCall(Func<int, string>)
OnCall
调用Do()
这是add_OnCall
CIL中的缩写实现。有趣的部分是它用于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
同样,Delegate.Remove
用于中remove_OnCall
。
要调用OnCall
in Do()
,它仅在加载arg之后调用最终的串联委托:
IL_0026: callvirt instance !1 class [mscorlib]System.Func`2<int32,string>::Invoke(!0)
最后,在Main
并不OnCall
令人惊讶地,在中,通过add_OnCall
在Foo
实例上调用方法来订阅事件。
这是一个一般性的答案,反映了默认行为:
话虽如此,每个提供事件的类都可以选择异步实现其事件。IDesign提供了一个名为的类EventsHelper
,可以简化此过程。
[注意]此链接要求您提供一个电子邮件地址以下载EventsHelper类。(我没有任何关系)
事件只是代表的数组。只要委托调用是同步的,事件也是同步的。
通常,事件是同步的。但是,也有一些例外,例如如果为null,则System.Timers.Timer.Elapsed
在ThreadPool
线程上引发事件SyncronisingObject
。
文件:http://msdn.microsoft.com/en-us/library/system.timers.timer.elapsed.aspx
只要您不手动启动第二个线程,C#中的事件就会同步运行(在两种情况下)。