从循环体重构多个 goto 语句

Refactor multiple goto statements from the loop body

我正在努力将以下 Fortran 77 子例程复制到 C# 方法中。主要问题是我试图摆脱 fortran 的 goto 语句。

fortran 到 C# 的转换看起来不错,但 goto 语句仍然存在。有没有一种方法可以将它们全部替换为条件语句或其他一些方法?谢谢。

这是 fortran 子例程:

C PROGRAM TEMP
      subroutine TEMP (acl,adu,aeff,c,cair,cb,cbare, 
     + cclo,count1,csum,di,ed,emcl,emsk,enbal, 
     + enbal2,ere,erel,esw,eswdif,eswphy,eswpot, 
     + evap,facl,fcl,fec,feff,food,h,hc,he,ht,htcl,icl,j, 
     + mbody,p,po,r1,r2,rbare,rcl, 
     + rclo,rclo2,rdcl,rdsk,rob,rsum,sex,sigm,sw,swf,swm, 
     + ta,tbody,tcl,tcore,tmrt,tsk,v,vb,vb1,vb2, 
     + vpa,vpts,wetsk,wd,wr,ws,wsum,xx) 
      real acl,adu,aeff,c(0:10),cair,cb,cbare, 
     + cclo,csum,di,ed,emcl,emsk,enbal, 
     + enbal2,ere,erel,esw,eswdif,eswphy,eswpot, 
     + evap,facl,fcl,fec,feff,food,h,hc,he,ht,htcl,icl, 
     + mbody,p,po,r1,r2,rbare,rcl, 
     + rclo,rclo2,rdcl,rdsk,rob,rsum,sigm,sw,swf,swm, 
     + ta,tbody,tcl,tcore(1:7),tmrt,tsk,v,vb,vb1,vb2, 
     + vpa,vpts,wetsk,wd,wr,ws,wsum,xx 
      integer count1,count3,j,sex 
      wetsk = 0. 
      adu = 0.203 * mbody ** 0.425 * ht ** 0.725 
      hc = 2.67 + ( 6.5 * v ** 0.67) 
      hc = hc * (p /po) ** 0.55 
      feff = 0.725 
C 
      facl = (- 2.36 + 173.51 * icl - 100.76 * icl * icl + 19.28 
     + * (icl ** 3.)) / 100. 
C 
      if (facl .gt.1.) facl = 1. 
      rcl = (icl/6.45)/facl 
      if (icl.ge.2.) y = 1. 
      if ((icl .gt. 0.6) .and. (icl .lt. 2.)) y = (ht - 0.2) / ht 
      if ((icl .le. 0.6) .and. (icl .gt. 0.3)) y = 0.5 
      if ((icl .le. 0.3) .and. (icl .gt. 0.)) y = 0.1 
      r2 = adu * (fcl - 1. + facl) / (2. * 3.14 * ht * y) 
      r1 = facl * adu / (2. * 3.14 * ht * y) 
      di = r2 - r1 
C TEMPERATURE
      do 90 j = 1,7 
      tsk = 34. 
      count1 = 0 
      tcl = (ta + tmrt + tsk) / 3. 
      count3 = 1 
      enbal2 = 0. 
   20 acl = adu * facl + adu * (fcl - 1.) 
      rclo2 = emcl*sigm *((tcl+273.2)** 4.-(tmrt+273.2)** 4.)*feff 
      htcl = 6.28 * ht * y * di / (rcl * alog(r2/r1) * acl) 
      tsk = 1. / htcl * (hc * (tcl - ta) + rclo2) + tcl 
C RADIATION 
      aeff = adu * feff 
      rbare = aeff * (1.-facl) * emsk * sigm * 
     + ((tmrt + 273.2) ** 4. - (tsk + 273.2) ** 4.) 
      rclo = feff * acl * emcl * sigm * 
     + ((tmrt + 273.2) ** 4. - (tcl + 273.2) ** 4.) 
      rsum = rbare + rclo 
C CONVECT
      cbare = hc * (ta - tsk) * adu * (1. - facl) 
      cclo = hc * (ta - tcl ) * acl 
      csum = cbare + cclo 
C CORE
      c(0) = h + ere 
      c(1) = adu * rob * cb 
      c(2) = 18. - 0.5 * tsk 
      c(3) = 5.28 * adu * c(2) 
      c(4) = 0.0208 * c(1) 
      c(5) = 0.76075 * c(1) 
      c(6) = c(3) - c(5) - tsk * c(4) 
      c(7) = - c(0) * c(2) - tsk * c(3) + tsk * c(5) 
      c(8) = c(6) * c(6) - 4. * c(4) * c(7) 
      c(9) = 5.28 * adu - c(5) - c(4) * tsk 
      c(10) = c(9) * c(9) - 4. * c(4) * 
     + (c(5) * tsk - c(0) - 5.28 * adu * tsk) 
C 
      if (tsk.eq.36.) tsk=36.01 
      tcore(7) = c(0) / (5.28 * adu + c(1) * 6.3 / 3600.) + tsk 
      tcore(3) = c(0) / (5.28 * adu + (c(1) * 6.3 / 3600.) / 
     + (1 + 0.5 * (34. -tsk))) + tsk 
      if (c(10) .lt. 0.) goto 22 
      tcore(6) = (- c(9) - c(10) ** 0.5) / (2. * c(4)) 
      tcore(1) = (- c(9) + c(10) ** 0.5) / (2. * c(4)) 
   22 if (c(8) .lt. 0.) goto 24 
      tcore(2) = (- c(6) + abs(c(8)) ** 0.5) / (2. * c(4)) 
      tcore(5) = (- c(6) - abs(c(8)) ** 0.5) / (2. * c(4)) 
   24 tcore(4) = c(0) / (5.28 * adu + c(1) * 1. / 40.) + tsk 
C TRANSPARENCE
      tbody = 0.1 * tsk + 0.9 * tcore (j) 
      swm = 304.94 * (tbody - 36.6) * adu / 3600000. 
      vpts = 6.11 * 10. ** (7.45 * tsk / (235. + tsk)) 
      if (tbody .le. 36.6) swm = 0. 
      swf = 0.7 * swm 
      if(sex .eq. 1) sw = swm 
      if(sex .eq. 2) sw = swf 
      eswphy = - sw * evap 
      he = 0.633 * hc / (p * cair) 
      fec = 1. / (1. + 0.92 * hc * rcl) 
      eswpot = he * (vpa - vpts) * adu * evap * fec 
      wetsk = eswphy / eswpot 
      if (wetsk .gt. 1.) wetsk = 1. 
      eswdif = eswphy - eswpot 
      if (eswdif .le. 0.) esw = eswpot 
      if (eswdif .gt. 0.) esw = eswphy 
      if (esw .gt. 0.) esw = 0. 
C DIFFERENCE
      rdsk = 0.79 * 10. ** 7. 
      rdcl = 0. 
      ed = evap / (rdsk + rdcl) * adu * (1 - wetsk) * (vpa-vpts) 
C VB 
      vb1 = 34. - tsk 
      vb2 = tcore(j) - 36.6 
      if (vb2 .lt.0.) vb2 = 0. 
      if (vb1 .lt.0.) vb1 = 0. 
      vb = (6.3 + 75. * (vb2)) / (1. + 0.5 * vb1) 
C BALANCE
      enbal = h + ed + ere + esw + csum + rsum + food 
C COVER
      if (count1 .eq.0) xx = 1. 
      if (count1 .eq.1) xx = 0.1 
      if (count1 .eq.2) xx = 0.01 
      if (count1 .eq.3) xx = 0.001 
      if (enbal .gt. 0.) tcl = tcl + xx 
      if (enbal .lt. 0.) tcl = tcl - xx 
      if ((enbal .le. 0.) .and. (enbal2 .gt. 0.)) goto 30 
      if ((enbal .ge. 0.) .and. (enbal2 .lt. 0.)) goto 30 
      enbal2 = enbal 
      count3 = count3 + 1 
C 
      if (count3 .gt. 200) goto 30 
      goto 20 
   30 if ((count1 .eq.0.).or.(count1.eq.1.).or.(count1.eq.2.)) then 
         count1 = count1 + 1. 
         enbal2 = 0. 
         goto 20 
      end if 
C 
      if (count1 .eq. 3.) then 
C 
         if ((j .eq. 2) .or. (j .eq. 5)) goto 40 
         if ((j .eq. 6) .or. (j .eq. 1)) goto 50 
         if (j .eq. 3) goto 60 
         if (j .eq. 7) goto 70 
         if (j .eq. 4) goto 80 
      end if 
   40 if (c(8) .lt. 0.) goto 90 
      if ((tcore(j) .ge. 36.6) .and. (tsk .le. 34.050)) goto 80 
      goto 90 
   50 if (c(10) .lt. 0. ) goto 90 
      if ((tcore(j) .ge. 36.6) .and. (tsk .gt. 33.850)) goto 80 
      goto 90 
   60 if ((tcore(j) .lt. 36.6) .and. (tsk .le. 34.000)) goto 80 
      goto 90 
   70 if ((tcore(j) .lt. 36.6) .and. (tsk .gt. 34.000)) goto 80 
      goto 90 
   80 if ((j .ne. 4) .and. (vb .ge. 91.)) goto 90 
      if ((j. eq. 4) .and. (vb .lt. 89.)) goto 90 
      if (vb .gt. 90.) vb = 90. 
C LOSSES
      ws = sw * 3600. * 1000. 
      if (ws .gt.2000.) ws = 2000. 
      wd = ed / evap * 3600. * (-1000.) 
      wr = erel / evap * 3600. * (-1000.) 
      wsum = ws + wr + wd 
      goto 100 
   90 continue 
  100 return 
      end 

这里是 C# 尝试复制上层 fortran 子例程:

using System;

public static class GlobalMembers_TEMP
{

//C PROGRAM TEMP
// --------------------------------------------
    public static void TEMP(acl, adu, aeff, c, cair, cb, cbare, cclo, count1, csum, di, ed , emcl , emsk , enbal , enbal2 , ere , erel , esw , eswdif , eswphy , eswpot , evap , facl , fcl , fec , feff , food , h , hc , he , ht , htcl , icl , j , mbody , p , po , r1 , r2 , rbare , rcl , rclo , rclo2 , rdcl , rdsk , rob , rsum , sex , sigm , sw , swf , swm , ta , tbody , tcl, tcore , tmrt , tsk , v , vb , vb1 , vb2 , vpa , vpts , wetsk , wd , wr , ws , wsum , xx)
    {
        float acl;
        float adu;
        float aeff;
        float[] c = new float[11];  // ???
        float cair;
        float cb;
        float cbare;
        float cclo;
        float csum;
        float di;
        float ed;
        float emcl;
        float emsk;
        float enbal;
        float enbal2;
        float ere;
        float erel;
        float esw;
        float eswdif;
        float eswphy;
        float eswpot;
        float evap;
        float facl;
        float fcl;
        float fec;
        float feff;
        float food;
        float h;
        float hc;
        float he;
        float ht;
        float htcl;
        float icl;
        float mbody;
        float p;
        float po;
        float r1;
        float r2;
        float rbare;
        float rcl;
        float rclo;
        float rclo2;
        float rdcl;
        float rdsk;
        float rob;
        float rsum;
        float sigm;
        float sw;
        float swf;
        float swm;
        float ta;
        float tbody;
        float tcl;
        float[] tcore = new float[7];   // ???
        float tmrt;
        float tsk;
        float v;
        float vb;
        float vb1;
        float vb2;
        float vpa;
        float vpts;
        float wetsk;
        float wd;
        float wr;
        float ws;
        float wsum;
        float xx;
        int count1;
        int count3;
        int j;
        int sex;
        wetsk = 0.0;
        adu = 0.203 * mbody * *0.425 * ht * *0.725;
        hc = 2.67 + (6.5 * v * *0.67);
        hc = hc * (p / po) * *0.55;
        feff = 0.725;
        //C rcl = icl / 6.45
        facl = (-2.36 + 173.51 * icl - 100.76 * icl * icl + 19.28 * (icl * *3.0)) / 100.0;
        //C
        if (facl > 1.0)
        {
            facl = 1.0;
        }
        rcl = (icl / 6.45) / facl;
        if (icl >= 2.0)
        {
            y = 1.0;
        }
        if ((icl > 0.6)) && ((icl < 2.0)) 
        {
            y = (ht - 0.2) / ht;
        }
        if ((icl <= 0.6)) && ((icl > 0.3)) 
        {
            y = 0.5;
        }
        if ((icl <= 0.3)) && ((icl > 0.0)) 
        {
            y = 0.1;
        }
        r2 = adu * (fcl - 1.0 + facl) / (2.0 * 3.14 * ht * y);
        r1 = facl * adu / (2.0 * 3.14 * ht * y);
        di = r2 - r1;
        //C TEMPERATURE
        for (90 j = 1, 7)
        {
            tsk = 34.0;
            count1 = 0;
            tcl = (ta + tmrt + tsk) / 3.0;
            count3 = 1;
            enbal2 = 0.0;
    g20:
            acl = adu * facl + adu * (fcl - 1.0);
            rclo2 = emcl * sigm * ((tcl + 273.2) * *4.0 - (tmrt + 273.2) * *4.0) * feff;
            htcl = 6.28 * ht * y * di / (rcl * alog(r2 / r1) * acl);
            tsk = 1.0 / htcl * (hc * (tcl - ta) + rclo2) + tcl;
            //C RADIATION
            aeff = adu * feff;
            rbare = aeff * (1.0 - facl) * emsk * sigm * ((tmrt + 273.2) * *4.0 - (tsk + 273.2) * *4.0);
            rclo = feff * acl * emcl * sigm * ((tmrt + 273.2) * *4.0 - (tcl + 273.2) * *4.0);
            rsum = rbare + rclo;
            //C CONVECT
            cbare = hc * (ta - tsk) * adu * (1.0 - facl);
            cclo = hc * (ta - tcl) * acl;
            csum = cbare + cclo;
            //C CORE
            c[0] = h + ere;
            c[1] = adu * rob * cb;
            c[2] = 18.0 - 0.5 * tsk;
            c[3] = 5.28 * adu * c[2];
            c[4] = 0.0208 * c[1];
            c[5] = 0.76075 * c[1];
            c[6] = c[3] - c[5] - tsk * c[4];
            c[7] = -c[0] * c[2] - tsk * c[3] + tsk * c[5];
            c[8] = c[6] * c[6] - 4.0 * c[4] * c[7];
            c[9] = 5.28 * adu - c[5] - c[4] * tsk;
            c[10] = c[9] * c[9] - 4.0 * c[4] * (c[5] * tsk - c[0] - 5.28 * adu * tsk);
            //C
            if (tsk == 36.0)
            {
                tsk = 36.01;
            }
            tcore[7] = c[0] / (5.28 * adu + c[1] * 6.3 / 3600.0) + tsk;
            tcore[3] = c[0] / (5.28 * adu + (c[1] * 6.3 / 3600.0) / (1 + 0.5 * (34.0 - tsk))) + tsk;
            if (c[10] < 0.0)
            {
                goto g22;
            }
            tcore[6] = (-c[9] - c[10] * *0.5) / (2.0 * c[4]);
            tcore[1] = (-c[9] + c[10] * *0.5) / (2.0 * c[4]);
    g22:
            if (c[8] < 0.0)
            {
                goto g24;
            }
            tcore[2] = (-c[6] + Math.Abs(c[8]) * *0.5) / (2.0 * c[4]);
            tcore[5] = (-c[6] - Math.Abs(c[8]) * *0.5) / (2.0 * c[4]);
    g24:
            tcore[4] = c[0] / (5.28 * adu + c[1] * 1.0 / 40.0) + tsk;
            //C TRANSPARENCE
            tbody = 0.1 * tsk + 0.9 * tcore[j];
            swm = 304.94 * (tbody - 36.6) * adu / 3600000.0;
            vpts = 6.11 * 10.0 * *(7.45 * tsk / (235.0 + tsk));
            if (tbody <= 36.6)
            {
                swm = 0.0;
            }
            swf = 0.7 * swm;
            if (sex == 1)
            {
                sw = swm;
            }
            if (sex == 2)
            {
                sw = swf;
            }
            eswphy = -sw * evap;
            he = 0.633 * hc / (p * cair);
            fec = 1.0 / (1.0 + 0.92 * hc * rcl);
            eswpot = he * (vpa - vpts) * adu * evap * fec;
            wetsk = eswphy / eswpot;
            if (wetsk > 1.0)
            {
                wetsk = 1.0;
            }
            eswdif = eswphy - eswpot;
            if (eswdif <= 0.0)
            {
                esw = eswpot;
            }
            if (eswdif > 0.0)
            {
                esw = eswphy;
            }
            if (esw > 0.0)
            {
                esw = 0.0;
            }
            //C DIFFERENCE
            rdsk = 0.79 * 10.0 * *7.0;
            rdcl = 0.0;
            ed = evap / (rdsk + rdcl) * adu * (1 - wetsk) * (vpa - vpts);
            //C VB
            vb1 = 34.0 - tsk;
            vb2 = tcore[j] - 36.6;
            if (vb2 < 0.0)
            {
                vb2 = 0.0;
            }
            if (vb1 < 0.0)
            {
                vb1 = 0.0;
            }
            vb = (6.3 + 75.0 * (vb2)) / (1.0 + 0.5 * vb1);
            //C BALANCE
            enbal = h + ed + ere + esw + csum + rsum + food;
            //C COVER
            if (count1 == 0)
            {
                xx = 1.0;
            }
            if (count1 == 1)
            {
                xx = 0.1;
            }
            if (count1 == 2)
            {
                xx = 0.01;
            }
            if (count1 == 3)
            {
                xx = 0.001;
            }
            if (enbal > 0.0)
            {
                tcl = tcl + xx;
            }
            if (enbal < 0.0)
            {
                tcl = tcl - xx;
            }
            if ((enbal <= 0.0)) && ((enbal2 > 0.0)) 
            {
                goto g30;
            }
            if ((enbal >= 0.0)) && ((enbal2 < 0.0)) 
            {
                goto g30;
            }
            enbal2 = enbal;
            count3 = count3 + 1;
            //C
            if (count3 > 200)
            {
                goto g30;
            }
            goto g20;
    g30:
            if ((count1 == 0.0))
            {
                || ((count1 == 1.0)) || ((count1 == 2.0))
                {
                count1 = count1 + 1.0;
                enbal2 = 0.0;
                goto g20;
                }
            }
            //C
            if (count1 == 3.0)
            {
                //C
                if ((j == 2))
                {
                    || ((j == 5)) goto g40;
                }
                if ((j == 6))
                {
                    || ((j == 1)) goto g50;
                }
                if (j == 3)
                {
                    goto g60;
                }
                if (j == 7)
                {
                    goto g70;
                }
                if (j == 4)
                {
                    goto g80;
                }
            }
    g40:
            if (c[8] < 0.0)
            {
                goto g90;
            }
            if ((tcore[j] >= 36.6)) && ((tsk <= 34.050))
            {
                goto g80;
            }
            goto g90;
    g50:
            if (c[10] < 0.0)
            {
                goto g90;
            }
            if ((tcore[j] >= 36.6)) && ((tsk > 33.850))
            {
                goto g80;
            }
            goto g90;
    g60:
            if ((tcore[j] < 36.6)) && ((tsk <= 34.000))
            {
                goto g80;
            }
            goto g90;
    g70:
            if ((tcore[j] < 36.6)) && ((tsk > 34.000))
            {
                goto g80;   
            }
            goto g90;
    g80:
            if ((j != 4)) && ((vb >= 91.0)) 
            {
                goto g90;
            }
            if ((j.eq.4)) && ((vb < 89.0))
            {
                 goto g90;
            }
            if (vb > 90.0)
            {
                vb = 90.0;
            }
            //C LOSSES
            ws = sw * 3600.0 * 1000.0;
            if (ws > 2000.0)
            {
                ws = 2000.0;
            }
            wd = ed / evap * 3600.0 * (-1000.0);
            wr = erel / evap * 3600.0 * (-1000.0);
            wsum = ws + wr + wd;
            goto g100;

        }
    g100:
        return;
    }
}

您可以尝试将此代码转换为状态机,其中每个状态代表循环内的单个 goto。

为此,您需要将您的方法变成一个 class,它包含所有参数和变量作为 class 字段,并且有一个构造函数来初始化适当的字段并(可选)运行"method".

我不会转换你的方法,因为它作为一个例子来说太大了,但我会给你以下内容:

原始未转换方法:

public static void Do(Int32 param1, Int32 param2)
{            
    Int32 loopI;
    Int32 outBefore, 
        outAfter,
        outGoto1 = 0,
        outGoto2 = 0;
    Int32[] outValues = new Int32[7];

    Console.WriteLine("METHOD:");

    Console.WriteLine("DoBeforeLoop");
    outBefore = param1 + param2;

    Boolean wasInGoto2 = false;

    for (loopI = 0; loopI < 7; loopI++)
    {
        Console.WriteLine("Iteration {0}", loopI);

        Console.WriteLine("FortranLoopMethodState.LoopCycleStart");
        outValues[loopI] = loopI;

    goto1:
        Console.WriteLine("FortranLoopMethodState.Goto1");
        outGoto1 = loopI + param1;

        if (wasInGoto2)
        {
            wasInGoto2 = false;
            goto end;
        }

        wasInGoto2 = true;
        Console.WriteLine("FortranLoopMethodState.Goto2");
        outGoto2 = loopI + param2;
        goto goto1;
    end:
        DoNothing(); // We don't use break, do we?
    }

    Console.WriteLine("DoAfterLoop");
    outAfter = param1 - param2;

    Console.WriteLine(outGoto1);
    Console.WriteLine(outGoto2);
}

转换后的方法:

public class ExecuteFortranMethod
{
    private enum FortranLoopMethodState
    {
        LoopCycleStart,
        Goto1,
        Goto2,
        LoopCycleEnded
    }

    #region Params

    private Int32 param1;
    private Int32 param2;

    #endregion


    #region Variables

    public Int32 loopI;
    public Int32 outBefore, 
        outAfter,
        outGoto1,
        outGoto2;
    public Int32[] outValues = new Int32[7];

    #endregion


    #region Constructors

    public ExecuteFortranMethod(Int32 param1, Int32 param2)
    {
        this.param1 = param1;
        this.param2 = param2;

        this.Invoke();
    }

    #endregion


    #region Methods

    private void Invoke()
    {
        Console.WriteLine("STATE MACHINE CLASS:");

        this.DoBeforeLoop();

        for (this.loopI = 0; this.loopI < 7; this.loopI++)
        {
            Console.WriteLine("Iteration {0}", this.loopI);

            var state = FortranLoopMethodState.LoopCycleStart;
            do
            {
                state = DoLoop(state);
            }
            while (state != FortranLoopMethodState.LoopCycleEnded);
        }

        this.DoAfterLoop();
    }

    #endregion


    #region "Method" body methods

    private void DoBeforeLoop()
    {
        Console.WriteLine("DoBeforeLoop");
        this.outBefore = this.param1 + this.param2;
    }

    private void DoAfterLoop()
    {
        Console.WriteLine("DoAfterLoop");
        this.outAfter = this.param1 - this.param2;
    }

    Boolean wasInGoto2;

    private FortranLoopMethodState DoLoop(FortranLoopMethodState state)
    {
        switch (state)
        {
            case FortranLoopMethodState.LoopCycleStart:
                {
                    Console.WriteLine("FortranLoopMethodState.LoopCycleStart");
                    this.outValues[this.loopI] = this.loopI;
                    return FortranLoopMethodState.Goto1;
                }
            case FortranLoopMethodState.Goto1:
                {
                    Console.WriteLine("FortranLoopMethodState.Goto1");
                    this.outGoto1 = this.loopI + this.param1;

                    if (this.wasInGoto2)
                    {
                        this.wasInGoto2 = false;
                        return FortranLoopMethodState.LoopCycleEnded;
                    }
                    return FortranLoopMethodState.Goto2;
                }
            case FortranLoopMethodState.Goto2:
                {
                    this.wasInGoto2 = true;
                    Console.WriteLine("FortranLoopMethodState.Goto2");
                    this.outGoto2 = this.loopI + this.param2;
                    return FortranLoopMethodState.Goto1;
                }
            default:
                throw new InvalidOperationException("The state is invalid");
        }
    }

    #endregion
}   

Program.cs

Do(10, 20);
Console.WriteLine();

var result = new ExecuteFortranMethod(10, 20);

Console.WriteLine(result.outGoto1);
Console.WriteLine(result.outGoto2);

Console.WriteLine("Press any key");
Console.ReadKey(true);    

如您所见,输出是等效的。我不会具体描述如何转移实际方法,因为这是一项乏味(但并非不真实)的任务,没有真正的捷径,即使阅读这个小例子,大部分想法也会很清楚。

P.S.1: 虽然没有真正的捷径(当然除了编写一些可以生成这种状态机的小工具 classes对于给定的代码),您可以通过一些 regular expressions 搜索和替换 (Ctrl+F) 来简化手动工作。例如,将模式 goto(\d+) 替换为 case State.Goto { 会将所有 goto 替换为 switch case 存根。

P.S.2: 如果 switch cases(gotos) 太多,你可能想用一些 Dictionary lookup.

P.S.3: 而且很多人已经指出了,我仍然建议你尝试理解原始代码流程并从头开始重写它。

循环内的 goto 意味着两件事:

  • 停止当前循环的执行(这就像使用 continue)
  • 跳过 goto 标签之前的所有内容(这就像使用 if)

理论上你可以使用一个大的 switch 语句而不是 if 语句,在每个情况下都没有中断(fall through 模式),所以你可以将 switch 值(创建一个变量)设置为正确的而不是执行 goto position 然后调用 continue.

但这与您在使用 goto 时遇到的问题是相同的逻辑并会导致相同的问题。对于没有编写代码的人来说,它是不可理解的、不可调试的、不可维护的。 3-4个月后,同一个人就更难了。

作为第一步,您应该尝试获取每个块并确定它到底做了什么,如果可能的话将它提取到一个 method/function 并取一个好名字。

当你完成后,你希望有一个巨大的 goto 混乱,里面有一些函数调用。尝试减少 if 语句的混乱。 g70 看起来像是一个可能的候选者,因为它有条件地执行 g80 的东西或跳过它并在 g90 继续,但没有详细查看它。

一旦你达到那个水平,你也可以制作执行图,一行(可能在电子表格中)为每个 goto 标签写下然后调用哪些函数,直到它到达另一个 goto。

好的重构的基础是对问题的良好理解,所以也许采访编写 pascal 代码的人来解释它的作用会对你有很大帮助。

代码完成后,看看你用代码做了什么,以及它真正做了什么,会很有趣!