zoukankan      html  css  js  c++  java
  • 【Emit基础】如何发射foreach代码?

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

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

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

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

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

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

        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 (ICompute com in computers)
                {
                    com.Add(a, b);
                }
            }
        }

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

    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:

    .method public hidebysig newslot virtual final instance void Add(int32 a, int32 b) cil managed
    {
        .maxstack 
    3
        .locals init (
            [
    0class TheTest.ICompute com,
            [
    1class [mscorlib]System.Collections.Generic.IEnumerator`1<class TheTest.ICompute> CS$5$0000,
            [
    2bool 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: callvirt instance 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.s L_0027
        L_0015: ldloc.
    1 
        L_0016: callvirt instance 
    !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: callvirt instance 
    void TheTest.ICompute::Add(int32, int32)
        L_0025: nop 
        L_0026: nop 
        L_0027: ldloc.
    1 
        L_0028: callvirt instance 
    bool [mscorlib]System.Collections.IEnumerator::MoveNext()
        L_002d: stloc.
    2 
        L_002e: ldloc.
    2 
        L_002f: brtrue.s L_0015
        L_0031: leave.s L_0043
        L_0033: ldloc.
    1 
        L_0034: ldnull 
        L_0035: ceq 
        L_0037: stloc.
    2 
        L_0038: ldloc.
    2 
        L_0039: brtrue.s L_0042
        L_003b: ldloc.
    1 
        
    L_003c: callvirt instance void [mscorlib]System.IDisposable::Dispose()
        L_0041: nop 
        L_0042: endfinally 
        L_0043: nop 
        L_0044: ret 
       
     .try L_0013 to L_0033 finally handler L_0033 to L_0043
    }

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

    .try L_0013 to L_0033 finally handler L_0033 to L_0043

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

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

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

     ILGenerator methodGen = ..... ;

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

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

     ILGenerator methodGen = ..... ;
     
    //开始try块
     methodGen.BeginExceptionBlock();
     
    //......
     
    //开始finally块
     methodGen.BeginFinallyBlock();
     
    //......
     
    //结束try/finally块
     methodGen.EndExceptionBlock(); 
  • 相关阅读:
    [整理]Cadence 生成带有网络追踪的 PDF 原理图
    [整理]FSM 有限状态机
    [原创]Quartus 中调用 Modelsim 波形仿真
    [原创]SPI 协议介绍以及基于 Verilog 的 IP 核实现
    [原创]Verilog 代码编程规范(个人用)
    [算法]线段树
    [算法]tarjan
    poj3280
    poj 3258 River Hopscotch
    [poj 1251]Jungle Roads
  • 原文地址:https://www.cnblogs.com/zhuweisky/p/1702961.html
Copyright © 2011-2022 走看看