`
feipigwang
  • 浏览: 770257 次
  • 性别: Icon_minigender_2
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

【Emit基础】如何发射foreach代码?

 
阅读更多

  对于集合的遍历,使用foreach是非常方便的,但是Emit动态生成foreach的代码就要复杂很多。它涉及到以下几个方面:

(1)IEnumerable<> 是所有可枚举类型的基础接口。

(2)IEnumerator<>,通过IEnumerable<> 接口的GetEnumerator方法可以获取枚举器IEnumerator<>,而对集合元素的遍历正是由IEnumerator<>的MoveNext方法完成的。

(3)遍历完成以后,需要调用IEnumerator<>的Dispose方法释放它。

(4)为了IEnumerator<>被正常释放,还需要使用try....finally块包含相应的代码。

下面我们来举个例子,比如对于如下的C#代码:

<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--> publicinterfaceICompute
{
voidAdd(inta,intb);
}
publicclassCompute:ICompute
{
privateICollection<ICompute>computers;

publicvoidAdd(inta,intb)
{
foreach(IComputecomincomputers)
{
com.Add(a,b);
}
}
}

Compute类的Add方法使用了foreach进行遍历操作,我们可以将Add方法的等价形式写出来:

<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->publicvirtualvoidAdd(intnum1,intnum2)
{
IEnumerator<ICompute>enumerator=this.computers.GetEnumerator();
try
{
while(enumerator.MoveNext())
{
enumerator.Current.Add(num1,num2);
}
}
finally
{
if(enumerator!=null)
{
enumerator.Dispose();
}
}
}

  那么为了Emit类似的代码,需要生成如下的IL:

<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->.methodpublichidebysignewslotvirtualfinalinstancevoidAdd(int32a,int32b)cilmanaged
{
.maxstack
3
.localsinit(
[
0]classTheTest.IComputecom,
[
1]class[mscorlib]System.Collections.Generic.IEnumerator`1<classTheTest.ICompute>CS$5$0000,
[
2]boolCS$4$0001)
L_0000:nop
L_0001:nop
L_0002:ldarg.
0
L_0003:ldfld
classclass[mscorlib]System.Collections.Generic.ICollection`1<classTheTest.ICompute>TheTest.Compute::computers
L_000d:callvirtinstanceclass[mscorlib]System.Collections.Generic.IEnumerator`1<!0>[mscorlib]System.Collections.Generic.IEnumerable`1<classTheTest.ICompute>::GetEnumerator()
L_0012:stloc.
1
L_0013:br.sL_0027
L_0015:ldloc.
1
L_0016:callvirtinstance
!0[mscorlib]System.Collections.Generic.IEnumerator`1<classTheTest.ICompute>::get_Current()
L_001b:stloc.
0
L_001c:nop
L_001d:ldloc.
0
L_001e:ldarg.
1
L_001f:ldarg.
2
L_0020:callvirtinstance
voidTheTest.ICompute::Add(int32,int32)
L_0025:nop
L_0026:nop
L_0027:ldloc.
1
L_0028:callvirtinstance
bool[mscorlib]System.Collections.IEnumerator::MoveNext()
L_002d:stloc.
2
L_002e:ldloc.
2
L_002f:brtrue.sL_0015
L_0031:leave.sL_0043
L_0033:ldloc.
1
L_0034:ldnull
L_0035:ceq
L_0037:stloc.
2
L_0038:ldloc.
2
L_0039:brtrue.sL_0042
L_003b:ldloc.
1
L_003c:callvirtinstancevoid[mscorlib]System.IDisposable::Dispose()
L_0041:nop
L_0042:endfinally
L_0043:nop
L_0044:ret
.tryL_0013toL_0033finallyhandlerL_0033toL_0043
}

  请注意红色代码部分,这与我们上面的描述是一致的。其它的IL代码的Emit相对简单,这里我们只提一下如何Emit最后这句try...finally块:

<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->.tryL_0013toL_0033finallyhandlerL_0033toL_0043

  对于try...catch...finnally块的标准Emit过程时这样的:

<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->ILGenerator methodGen = ..... ;
//开始try块
methodGen.BeginExceptionBlock();
//......
//开始catch块
methodGen.BeginCatchBlock(typeof(Exception));
//......
//开始finally块
methodGen.BeginFinallyBlock();
//......
//结束try/Catch/finally块
methodGen.EndExceptionBlock();

如果只有try...catch...,则

<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->ILGeneratormethodGen=.....;

//开始try块
methodGen.BeginExceptionBlock();
//......
//开始catch块
methodGen.BeginCatchBlock(typeof(Exception));
//......
//结束try/Catch块
methodGen.EndExceptionBlock();

如果只有try...finnally...,则

<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->ILGeneratormethodGen=.....;
//开始try块
methodGen.BeginExceptionBlock();
//......
//开始finally块
methodGen.BeginFinallyBlock();
//......
//结束try/finally块
methodGen.EndExceptionBlock();

分享到:
评论

相关推荐

    通过vue手动封装on、emit、off的代码详解

    EventList[eventName].forEach((cb) =&gt; { cb(params); }); }; ``` #### 3. 封装$off 封装$off需要根据事件名和回调函数的存在与否来决定移除监听器的策略。如果只提供事件名,那么移除该事件名下的所有回调函数...

    把字符串变成可执行代码

    在编程领域,将字符串转换为可执行代码是一项关键技能,特别是在动态语言中。这个过程通常称为“代码评估”或“代码动态执行”。在Python、JavaScript等语言中,我们可以找到这样的功能,使得程序能够根据运行时的...

    C++ 、Qt 代码质量检查表综合 V0.5.doc

    变量定义与函数返回类型应保持一致,优先使用qAbs等Qt提供的函数替换C库函数,避免使用foreach语句,并在发送信号时明确使用emit宏。同时,代码中的常量需与工程定义一致。 在逻辑处理和健壮性方面,检查表着重于...

    在Node.js中编写自己的事件发射器代码:循序渐进指南

    事件发射器允许对象在特定事件发生时发出通知,其他部分的代码可以监听这些事件并作出响应。这使得代码模块化,降低了组件之间的耦合度。在Node.js中,一个事件发射器通常包含两个主要方法:`emit`用于触发事件,`on...

    js代码-蚂蚁金服前端面试题 // 题目 4:实现一个基本的 event-emitter。 class EE { emit(name, ...params) { } // once 指只通知一次 once(name, func) { } on(name, func) { } off(name, func) { } }

    在JavaScript编程中,EventEmitter(事件发射器)是一种常见的设计模式,它允许对象在特定时刻发出事件,并让其他部分的代码订阅这些事件以作出响应。这个模式在许多库和框架中都有应用,如Node.js的EventEmitter类...

    详解如何模拟实现node中的Events模块(通俗易懂版)

    在Node.js开发中,Events模块是一个核心组件,提供了事件发射、监听和派发的机制,它基于观察者模式设计。观察者模式是一种设计模式,其中一个对象(称为主题)维护一系列依赖于它的其他对象(观察者),当主题状态...

    如何获取C#中方法的执行时间以及其代码注入详解

    我们可以使用命名空间System.Reflection.Emit中的类来动态创建程序集、类型和成员。例如,我们可以使用Mono.Cecil类库来动态读取并修改已经生成的IL文件。 下面是一个使用Mono.Cecil类库来注入Stopwatch的代码: `...

    23个设计模式C#代码

    C#的foreach语句就是对迭代器模式的内置支持。 15. **备忘录模式**:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可将对象恢复到原先保存的状态。C#中,可以使用序列...

    c#动态编译生成

    在C#编程中,动态编译是一个非常有用的特性,它允许程序在运行时生成和编译代码。这种技术主要用于各种场景,例如插件系统、代码生成、自动化测试等。本篇将详细介绍两种C#中实现动态编译的方法,并通过一个名为`...

    10-手写event-bus.md

    - **代码规范性**:代码是开发者专业性的直观体现,规范的代码不仅有助于提升项目的可读性,还能减少潜在的错误。 - **功能完整性**:能够编写出功能齐全的代码体现了开发者对语言特性、库函数和API等的熟练掌握。 -...

    js代码-eventBus

    在上面的代码中,`EventBus` 类包含了`on`、`emit`和`off`方法。`on`方法用于订阅事件,`emit`方法用于触发事件,`off`方法用于取消订阅。`main.js` 可能会利用这个类来注册事件监听器和触发事件。 `README.txt` ...

    vue&jeecg.md

    #### 一、Vue与Jeecg结合使用的基础概念 **Vue.js** 是一款轻量级的前端框架,主要用于构建用户界面。它的核心库专注于视图层,易于上手,同时也非常灵活,能够与第三方库或现有的项目进行集成。 **Jeecg** 是一个...

    websockt模拟定时告警和聊天

    ### WebSocket基础 WebSocket协议定义了一种在单个TCP连接上进行全双工通信的协议。相比于传统的HTTP请求-响应模式,WebSocket提供了更低的延迟和更高的效率,因为一旦连接建立,数据就可以在客户端和服务器之间...

    js代码-手写EventBus

    this.events[eventName].forEach(callback =&gt; callback(data)); } } } ``` 3. **使用EventBus** - 注册事件监听器:在需要响应事件的地方调用`on`方法,传入事件名和处理函数。 - 触发事件:在需要发送消息的...

    vue通信方式EventBus的实现代码详解

    上述代码定义了一个`EventBus`类,包含了`on`、`emit`、`once`和`off`方法。`on`用于添加监听器,`emit`用于触发事件,`once`用于添加只执行一次的监听器,而`off`用于移除监听器。`event`属性是一个存储事件与监听...

    js代码-手写订阅者模式

    `publish` 或 `emit` 方法则用于触发事件。它接收一个事件名作为参数,并调用所有订阅了该事件的处理函数。 `README.txt` 文件可能包含了对`main.js`中代码的解释和使用示例。它可能会指导如何创建订阅者(订阅事件...

    php-yml-源码.rar

    这个扩展提供了一组函数,如`yaml_parse_file`和`yaml_emit`,分别用于解析YAML文件和生成YAML字符串。PHP的YAML扩展通常基于libyaml库,一个高效的C语言实现的YAML解析器和生成器。 2. YAML解析过程 解析YAML文件...

Global site tag (gtag.js) - Google Analytics