【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/ />--> public interface ICompute
{
void Add( int a, int b);
}
public class Compute : ICompute
{
private ICollection < ICompute > computers;

public void Add( int a, int b)
{
foreach (IComputecom in computers)
{
com.Add(a,b);
}
}
}

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

<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--> public virtual void Add( int num1, int num2)
{
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/ />--> .method public hidebysignewslot virtual finalinstance void Add(int32a,int32b)cilmanaged
{
.maxstack
3
.localsinit(
[
0 ] class TheTest.IComputecom,
[
1 ] class [mscorlib]System.Collections.Generic.IEnumerator` 1 < class TheTest.ICompute > CS$ 5 $ 0000 ,
[
2 ] bool CS$ 4 $ 0001 )
L_0000:nop
L_0001:nop
L_0002:ldarg.
0
L_0003:ldfld
class class[mscorlib]System.Collections.Generic.ICollection`1 < class TheTest.ICompute > TheTest.Compute::computers
L_000d:callvirtinstance class [mscorlib]System.Collections.Generic.IEnumerator` 1 <! 0 > [mscorlib]System.Collections.Generic.IEnumerable` 1 < class TheTest.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 < class TheTest.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
void TheTest.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:callvirtinstance void [mscorlib]System.IDisposable::Dispose()
L_0041:nop
L_0042:endfinally
L_0043:nop
L_0044:ret
. tryL_0013toL_0033finally handlerL_0033toL_0043
}

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

<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--> . try L_0013toL_0033 finally handlerL_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/ />--> ILGenerator methodGen = .....;

// 开始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/ />--> ILGenerator methodGen = .....;
// 开始try块
methodGen.BeginExceptionBlock();
// ......
// 开始finally块
methodGen.BeginFinallyBlock();
// ......
// 结束try/finally块
methodGen.EndExceptionBlock();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值