【Emit基础】IL中发布、订阅、触发事件
在下面的例子中,我定义了一个事件发布类Computer,事件订阅者ComputerManager。Computer发布了一个OnAction事件,并且该事件在Increase方法被调用时触发。ComputerManager接收到事件通知时,会将成员字段handleCount增加1.
先看Computer的定义:
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->.namespaceILTest
{
.classpublicautoansibeforefieldinitComputerextends[mscorlib]System.Object
{
//事件对应的委托实例
.fieldprivateclass[ESBasic]ESBasic.CbSimpleonAction
//订阅事件
.methodpublichidebysigspecialnameinstancevoidadd_onAction(class[ESBasic]ESBasic.CbSimple)cilmanagedsynchronized
{
ldarg.0
dup
ldfldclass[ESBasic]ESBasic.CbSimpleILTest.Computer::onAction
ldarg.1
callclass[mscorlib]System.Delegate[mscorlib]System.Delegate::Combine(class[mscorlib]System.Delegate,class[mscorlib]System.Delegate)
castclass[ESBasic]ESBasic.CbSimple
stfldclass[ESBasic]ESBasic.CbSimpleILTest.Computer::onAction
ret
}
//取消订阅
.methodpublichidebysigspecialnameinstancevoidremove_onAction(class[ESBasic]ESBasic.CbSimple)cilmanagedsynchronized
{
ldarg.0
dup
ldfldclass[ESBasic]ESBasic.CbSimpleILTest.Computer::onAction
ldarg.1
callclass[mscorlib]System.Delegate[mscorlib]System.Delegate::Remove(class[mscorlib]System.Delegate,class[mscorlib]System.Delegate)
castclass[ESBasic]ESBasic.CbSimple
stfldclass[ESBasic]ESBasic.CbSimpleILTest.Computer::onAction
ret
}
//发布事件
.event[ESBasic]ESBasic.CbSimpleOnAction
{
.addoninstancevoidILTest.Computer::add_onAction(class[ESBasic]ESBasic.CbSimple)
.removeoninstancevoidILTest.Computer::remove_onAction(class[ESBasic]ESBasic.CbSimple)
}
//*******************Ctor**********************************************
.methodpublichidebysigspecialnamertspecialnameinstancevoid.ctor()cilmanaged
{
ldarg.0
callinstancevoid[mscorlib]System.Object::.ctor()
ret
}
//*******************Method********************************************
.methodpublichidebysiginstancevoidIncrease()cilmanaged
{
//触发事件
ldarg.0
ldfldclass[ESBasic]ESBasic.CbSimpleILTest.Computer::onAction
ldnull
ceq
brtrue.sL_001
ldarg.0
ldfldclass[ESBasic]ESBasic.CbSimpleILTest.Computer::onAction
callvirtinstancevoid[ESBasic]ESBasic.CbSimple::Invoke()
nop
L_001:ret
}
}
}
{
.classpublicautoansibeforefieldinitComputerextends[mscorlib]System.Object
{
//事件对应的委托实例
.fieldprivateclass[ESBasic]ESBasic.CbSimpleonAction
//订阅事件
.methodpublichidebysigspecialnameinstancevoidadd_onAction(class[ESBasic]ESBasic.CbSimple)cilmanagedsynchronized
{
ldarg.0
dup
ldfldclass[ESBasic]ESBasic.CbSimpleILTest.Computer::onAction
ldarg.1
callclass[mscorlib]System.Delegate[mscorlib]System.Delegate::Combine(class[mscorlib]System.Delegate,class[mscorlib]System.Delegate)
castclass[ESBasic]ESBasic.CbSimple
stfldclass[ESBasic]ESBasic.CbSimpleILTest.Computer::onAction
ret
}
//取消订阅
.methodpublichidebysigspecialnameinstancevoidremove_onAction(class[ESBasic]ESBasic.CbSimple)cilmanagedsynchronized
{
ldarg.0
dup
ldfldclass[ESBasic]ESBasic.CbSimpleILTest.Computer::onAction
ldarg.1
callclass[mscorlib]System.Delegate[mscorlib]System.Delegate::Remove(class[mscorlib]System.Delegate,class[mscorlib]System.Delegate)
castclass[ESBasic]ESBasic.CbSimple
stfldclass[ESBasic]ESBasic.CbSimpleILTest.Computer::onAction
ret
}
//发布事件
.event[ESBasic]ESBasic.CbSimpleOnAction
{
.addoninstancevoidILTest.Computer::add_onAction(class[ESBasic]ESBasic.CbSimple)
.removeoninstancevoidILTest.Computer::remove_onAction(class[ESBasic]ESBasic.CbSimple)
}
//*******************Ctor**********************************************
.methodpublichidebysigspecialnamertspecialnameinstancevoid.ctor()cilmanaged
{
ldarg.0
callinstancevoid[mscorlib]System.Object::.ctor()
ret
}
//*******************Method********************************************
.methodpublichidebysiginstancevoidIncrease()cilmanaged
{
//触发事件
ldarg.0
ldfldclass[ESBasic]ESBasic.CbSimpleILTest.Computer::onAction
ldnull
ceq
brtrue.sL_001
ldarg.0
ldfldclass[ESBasic]ESBasic.CbSimpleILTest.Computer::onAction
callvirtinstancevoid[ESBasic]ESBasic.CbSimple::Invoke()
nop
L_001:ret
}
}
}
再看ComputerManager实现:
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->.namespaceILTest
{
.classpublicautoansibeforefieldinitComputerManagerextends[mscorlib]System.Object
{
.fieldprivateclass[ILTest]ILTest.Computercomputer
.fieldprivateint32handleCount
.methodpublichidebysigspecialnamertspecialnameinstancevoid.ctor(class[ILTest]ILTest.Computer)cilmanaged
{
ldarg.0
ldarg.1
stfldclass[ILTest]ILTest.ComputerILTest.ComputerManager::computer
ldarg.0
ldc.i4.0
stfldint32ILTest.ComputerManager::handleCount
//调用基类ctor
ldarg.0
callinstancevoid[mscorlib]System.Object::.ctor()
//预定事件
ldarg.0
ldfldclass[ILTest]ILTest.Computer[ILTest]ILTest.ComputerManager::computer
ldarg.0
ldftninstancevoidILTest.ComputerManager::HandleAction()
newobjinstancevoid[ESBasic]ESBasic.CbSimple::.ctor(object,nativeint)//生成委托实例需要两个参数:目标对象和要调用的方法的指针
callvirtinstancevoidILTest.Computer::add_onAction(class[ESBasic]ESBasic.CbSimple)
ret
}
.methodpublichidebysiginstancevoidHandleAction()cilmanaged
{
ldarg.0
dup
ldfldint32ILTest.ComputerManager::handleCount
ldc.i4.1
add
stfldint32ILTest.ComputerManager::handleCount
ret
}
.methodpublichidebysiginstanceint32GetHandleCount()cilmanaged
{
ldarg.0
ldfldint32ILTest.ComputerManager::handleCount
ret
}
}
}
{
.classpublicautoansibeforefieldinitComputerManagerextends[mscorlib]System.Object
{
.fieldprivateclass[ILTest]ILTest.Computercomputer
.fieldprivateint32handleCount
.methodpublichidebysigspecialnamertspecialnameinstancevoid.ctor(class[ILTest]ILTest.Computer)cilmanaged
{
ldarg.0
ldarg.1
stfldclass[ILTest]ILTest.ComputerILTest.ComputerManager::computer
ldarg.0
ldc.i4.0
stfldint32ILTest.ComputerManager::handleCount
//调用基类ctor
ldarg.0
callinstancevoid[mscorlib]System.Object::.ctor()
//预定事件
ldarg.0
ldfldclass[ILTest]ILTest.Computer[ILTest]ILTest.ComputerManager::computer
ldarg.0
ldftninstancevoidILTest.ComputerManager::HandleAction()
newobjinstancevoid[ESBasic]ESBasic.CbSimple::.ctor(object,nativeint)//生成委托实例需要两个参数:目标对象和要调用的方法的指针
callvirtinstancevoidILTest.Computer::add_onAction(class[ESBasic]ESBasic.CbSimple)
ret
}
.methodpublichidebysiginstancevoidHandleAction()cilmanaged
{
ldarg.0
dup
ldfldint32ILTest.ComputerManager::handleCount
ldc.i4.1
add
stfldint32ILTest.ComputerManager::handleCount
ret
}
.methodpublichidebysiginstanceint32GetHandleCount()cilmanaged
{
ldarg.0
ldfldint32ILTest.ComputerManager::handleCount
ret
}
}
}
最后,我们写个Main方法来测试一下:
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->.namespaceILTest
{
.classprivateautoansibeforefieldinitMainClass
{
.methodpublichidebysigstaticvoidMain(string[]args)cilmanaged
{
.entrypoint
.localsinit
(
[0]class[ILTest]ILTest.Computercomputer,
[1]class[ILTest]ILTest.ComputerManagercomputerManager,
[2]int32count
)
newobjinstancevoid[ILTest]ILTest.Computer::.ctor()
stloc.0
ldloc.0
newobjinstancevoid[ILTest]ILTest.ComputerManager::.ctor(class[ILTest]ILTest.Computer)
stloc.1
ldloc.0
dup
dup
callinstancevoid[ILTest]ILTest.Computer::Increase()
callinstancevoid[ILTest]ILTest.Computer::Increase()
callinstancevoid[ILTest]ILTest.Computer::Increase()
ldloc.1
callinstanceint32[ILTest]ILTest.ComputerManager::GetHandleCount()
stloc.2
ldloca.s2
callinstancestring[mscorlib]System.Int32::ToString()
callvoid[mscorlib]System.Console::WriteLine(string)
callstring[mscorlib]System.Console::ReadLine()
pop
ret
}
}
}
{
.classprivateautoansibeforefieldinitMainClass
{
.methodpublichidebysigstaticvoidMain(string[]args)cilmanaged
{
.entrypoint
.localsinit
(
[0]class[ILTest]ILTest.Computercomputer,
[1]class[ILTest]ILTest.ComputerManagercomputerManager,
[2]int32count
)
newobjinstancevoid[ILTest]ILTest.Computer::.ctor()
stloc.0
ldloc.0
newobjinstancevoid[ILTest]ILTest.ComputerManager::.ctor(class[ILTest]ILTest.Computer)
stloc.1
ldloc.0
dup
dup
callinstancevoid[ILTest]ILTest.Computer::Increase()
callinstancevoid[ILTest]ILTest.Computer::Increase()
callinstancevoid[ILTest]ILTest.Computer::Increase()
ldloc.1
callinstanceint32[ILTest]ILTest.ComputerManager::GetHandleCount()
stloc.2
ldloca.s2
callinstancestring[mscorlib]System.Int32::ToString()
callvoid[mscorlib]System.Console::WriteLine(string)
callstring[mscorlib]System.Console::ReadLine()
pop
ret
}
}
}
main方法中调用了Increase方法三次,表示OnAction事件将被触发三次,所以运行后输出的结果是3。
如果你想使用IL进行应用程序开发,那么我推荐你使用开发环境SharpDevelop,对IL的支持还是不错的(遗憾的是还不支持对IL的代码提示),截图如下: