【Emit基础】IL中发布、订阅、触发事件
在下面的例子中,我定义了一个事件发布类Computer,事件订阅者ComputerManager。Computer发布了一个OnAction事件,并且该事件在Increase方法被调用时触发。ComputerManager接收到事件通知时,会将成员字段handleCount增加1.
先看Computer的定义:
.namespace ILTest
{
.class public auto ansi beforefieldinit Computer extends [mscorlib]System.Object
{
//事件对应的委托实例
.field private class [ESBasic]ESBasic.CbSimple onAction
//订阅事件
.method public hidebysig specialname instance void add_onAction(class [ESBasic]ESBasic.CbSimple) cil managed synchronized
{
ldarg.0
dup
ldfld class [ESBasic]ESBasic.CbSimple ILTest.Computer::onAction
ldarg.1
call class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate, class [mscorlib]System.Delegate)
castclass [ESBasic]ESBasic.CbSimple
stfld class [ESBasic]ESBasic.CbSimple ILTest.Computer::onAction
ret
}
//取消订阅
.method public hidebysig specialname instance void remove_onAction(class [ESBasic]ESBasic.CbSimple) cil managed synchronized
{
ldarg.0
dup
ldfld class [ESBasic]ESBasic.CbSimple ILTest.Computer::onAction
ldarg.1
call class [mscorlib]System.Delegate [mscorlib]System.Delegate::Remove(class [mscorlib]System.Delegate, class [mscorlib]System.Delegate)
castclass [ESBasic]ESBasic.CbSimple
stfld class [ESBasic]ESBasic.CbSimple ILTest.Computer::onAction
ret
}
//发布事件
.event [ESBasic]ESBasic.CbSimple OnAction
{
.addon instance void ILTest.Computer::add_onAction(class [ESBasic]ESBasic.CbSimple)
.removeon instance void ILTest.Computer::remove_onAction(class [ESBasic]ESBasic.CbSimple)
}
//******************* Ctor **********************************************
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed
{
ldarg.0
call instance void [mscorlib]System.Object::.ctor()
ret
}
//******************* Method ********************************************
.method public hidebysig instance void Increase() cil managed
{
//触发事件
ldarg.0
ldfld class [ESBasic]ESBasic.CbSimple ILTest.Computer::onAction
ldnull
ceq
brtrue.s L_001
ldarg.0
ldfld class [ESBasic]ESBasic.CbSimple ILTest.Computer::onAction
callvirt instance void [ESBasic]ESBasic.CbSimple::Invoke()
nop
L_001: ret
}
}
}
{
.class public auto ansi beforefieldinit Computer extends [mscorlib]System.Object
{
//事件对应的委托实例
.field private class [ESBasic]ESBasic.CbSimple onAction
//订阅事件
.method public hidebysig specialname instance void add_onAction(class [ESBasic]ESBasic.CbSimple) cil managed synchronized
{
ldarg.0
dup
ldfld class [ESBasic]ESBasic.CbSimple ILTest.Computer::onAction
ldarg.1
call class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate, class [mscorlib]System.Delegate)
castclass [ESBasic]ESBasic.CbSimple
stfld class [ESBasic]ESBasic.CbSimple ILTest.Computer::onAction
ret
}
//取消订阅
.method public hidebysig specialname instance void remove_onAction(class [ESBasic]ESBasic.CbSimple) cil managed synchronized
{
ldarg.0
dup
ldfld class [ESBasic]ESBasic.CbSimple ILTest.Computer::onAction
ldarg.1
call class [mscorlib]System.Delegate [mscorlib]System.Delegate::Remove(class [mscorlib]System.Delegate, class [mscorlib]System.Delegate)
castclass [ESBasic]ESBasic.CbSimple
stfld class [ESBasic]ESBasic.CbSimple ILTest.Computer::onAction
ret
}
//发布事件
.event [ESBasic]ESBasic.CbSimple OnAction
{
.addon instance void ILTest.Computer::add_onAction(class [ESBasic]ESBasic.CbSimple)
.removeon instance void ILTest.Computer::remove_onAction(class [ESBasic]ESBasic.CbSimple)
}
//******************* Ctor **********************************************
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed
{
ldarg.0
call instance void [mscorlib]System.Object::.ctor()
ret
}
//******************* Method ********************************************
.method public hidebysig instance void Increase() cil managed
{
//触发事件
ldarg.0
ldfld class [ESBasic]ESBasic.CbSimple ILTest.Computer::onAction
ldnull
ceq
brtrue.s L_001
ldarg.0
ldfld class [ESBasic]ESBasic.CbSimple ILTest.Computer::onAction
callvirt instance void [ESBasic]ESBasic.CbSimple::Invoke()
nop
L_001: ret
}
}
}
再看ComputerManager实现:
.namespace ILTest
{
.class public auto ansi beforefieldinit ComputerManager extends [mscorlib]System.Object
{
.field private class [ILTest]ILTest.Computer computer
.field private int32 handleCount
.method public hidebysig specialname rtspecialname instance void .ctor(class [ILTest]ILTest.Computer) cil managed
{
ldarg.0
ldarg.1
stfld class [ILTest]ILTest.Computer ILTest.ComputerManager::computer
ldarg.0
ldc.i4.0
stfld int32 ILTest.ComputerManager::handleCount
//调用基类ctor
ldarg.0
call instance void [mscorlib]System.Object::.ctor()
//预定事件
ldarg.0
ldfld class [ILTest]ILTest.Computer [ILTest]ILTest.ComputerManager::computer
ldarg.0
ldftn instance void ILTest.ComputerManager::HandleAction()
newobj instance void [ESBasic]ESBasic.CbSimple::.ctor(object ,native int)//生成委托实例需要两个参数:目标对象和要调用的方法的指针
callvirt instance void ILTest.Computer::add_onAction(class [ESBasic]ESBasic.CbSimple)
ret
}
.method public hidebysig instance void HandleAction() cil managed
{
ldarg.0
dup
ldfld int32 ILTest.ComputerManager::handleCount
ldc.i4.1
add
stfld int32 ILTest.ComputerManager::handleCount
ret
}
.method public hidebysig instance int32 GetHandleCount() cil managed
{
ldarg.0
ldfld int32 ILTest.ComputerManager::handleCount
ret
}
}
}
{
.class public auto ansi beforefieldinit ComputerManager extends [mscorlib]System.Object
{
.field private class [ILTest]ILTest.Computer computer
.field private int32 handleCount
.method public hidebysig specialname rtspecialname instance void .ctor(class [ILTest]ILTest.Computer) cil managed
{
ldarg.0
ldarg.1
stfld class [ILTest]ILTest.Computer ILTest.ComputerManager::computer
ldarg.0
ldc.i4.0
stfld int32 ILTest.ComputerManager::handleCount
//调用基类ctor
ldarg.0
call instance void [mscorlib]System.Object::.ctor()
//预定事件
ldarg.0
ldfld class [ILTest]ILTest.Computer [ILTest]ILTest.ComputerManager::computer
ldarg.0
ldftn instance void ILTest.ComputerManager::HandleAction()
newobj instance void [ESBasic]ESBasic.CbSimple::.ctor(object ,native int)//生成委托实例需要两个参数:目标对象和要调用的方法的指针
callvirt instance void ILTest.Computer::add_onAction(class [ESBasic]ESBasic.CbSimple)
ret
}
.method public hidebysig instance void HandleAction() cil managed
{
ldarg.0
dup
ldfld int32 ILTest.ComputerManager::handleCount
ldc.i4.1
add
stfld int32 ILTest.ComputerManager::handleCount
ret
}
.method public hidebysig instance int32 GetHandleCount() cil managed
{
ldarg.0
ldfld int32 ILTest.ComputerManager::handleCount
ret
}
}
}
最后,我们写个Main方法来测试一下:
.namespace ILTest
{
.class private auto ansi beforefieldinit MainClass
{
.method public hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.locals init
(
[0] class [ILTest]ILTest.Computer computer,
[1] class [ILTest]ILTest.ComputerManager computerManager,
[2] int32 count
)
newobj instance void [ILTest]ILTest.Computer::.ctor()
stloc.0
ldloc.0
newobj instance void [ILTest]ILTest.ComputerManager::.ctor(class [ILTest]ILTest.Computer)
stloc.1
ldloc.0
dup
dup
call instance void [ILTest]ILTest.Computer::Increase()
call instance void [ILTest]ILTest.Computer::Increase()
call instance void [ILTest]ILTest.Computer::Increase()
ldloc.1
call instance int32 [ILTest]ILTest.ComputerManager::GetHandleCount()
stloc.2
ldloca.s 2
call instance string [mscorlib]System.Int32::ToString()
call void [mscorlib]System.Console::WriteLine( string )
call string [mscorlib]System.Console::ReadLine( )
pop
ret
}
}
}
{
.class private auto ansi beforefieldinit MainClass
{
.method public hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.locals init
(
[0] class [ILTest]ILTest.Computer computer,
[1] class [ILTest]ILTest.ComputerManager computerManager,
[2] int32 count
)
newobj instance void [ILTest]ILTest.Computer::.ctor()
stloc.0
ldloc.0
newobj instance void [ILTest]ILTest.ComputerManager::.ctor(class [ILTest]ILTest.Computer)
stloc.1
ldloc.0
dup
dup
call instance void [ILTest]ILTest.Computer::Increase()
call instance void [ILTest]ILTest.Computer::Increase()
call instance void [ILTest]ILTest.Computer::Increase()
ldloc.1
call instance int32 [ILTest]ILTest.ComputerManager::GetHandleCount()
stloc.2
ldloca.s 2
call instance string [mscorlib]System.Int32::ToString()
call void [mscorlib]System.Console::WriteLine( string )
call string [mscorlib]System.Console::ReadLine( )
pop
ret
}
}
}
main方法中调用了Increase方法三次,表示OnAction事件将被触发三次,所以运行后输出的结果是3。
如果你想使用IL进行应用程序开发,那么我推荐你使用开发环境SharpDevelop,对IL的支持还是不错的(遗憾的是还不支持对IL的代码提示),截图如下: