【问题标题】:How to rewrite Java [continue <label> and break <label>] in C#?如何在 C# 中重写 Java [continue <label> and break <label>]?
【发布时间】:2011-07-20 02:36:03
【问题描述】:

在 Java 中它是这样写的..当我移植这段代码时......意识到没有这样的东西 break &lt;label&gt;continue &lt;label&gt;

我知道这些命令不包括在内,因为在使用带有命令的 goto 时必须有一种更简洁的方法。

但我最终使用.. 下面的 C# 代码以任何方式重写它?

Java 代码

for(JClass c : classes) {
    for(JMethod m : c.getMethods()) {
        JCode code = m.getCode();
        if(code == null)
            continue;
        label: for(int index = 0; index < code.getExceptionLookupTable().length; index++) {
            JException e = code.getExceptionTable().get(index);
            for(int index2 = e.getStartIndex(); index2 < e.getEndIndex(); index2++)
                if(code.getInstruction(index2).getOpcode() == NEW && ((NEW) code.getInstruction(index2)).getType().equals("java/lang/RuntimeException"))
                    continue label;
                if(e.getCatchTypeClassName().equals("java/lang/RuntimeException")) {
                    for(int index = e.getHandlerIndex(); index < code.getInstrLength(); index++) {
                        JInstruction instr = code.getInstruction(index);
                        if(instr.getOpcode() == ATHROW)
                            break;
                        else if(instr instanceof ReturnInstruction)
                            break label;
                    }
                    removeStuff(code, ei--);
                }
            }
    }
}

C# 代码。

foreach(JClass c in classes) {
    foreach(JMethod m in c.getMethods()) {
        JCode code = m.getCode();
        if(code == null)
            continue;

        for(int index = 0; index < code.getExceptionTable().Length; index++) {
            bool continueELoop = false;
            bool breakELoop = false;
            JException e = code.getExceptionTable().get(index);
            for(int index2 = e.getStartIndex(); index2 < e.getEndIndex(); index2++) {
                if(code.getInstruction(index2).getOpcode() == JInstructions.NEW && ((NEW) code.getInstruction(index2)).getType().Equals("java/lang/RuntimeException")) {
                    continueELoop = true;
                    break;
                }
            }
            if(continueELoop) continue;

            if(e.getCatchTypeClassName().Equals("java/lang/RuntimeException")) {
                for(int index = e.getHandlerIndex(); index < code.getInstrLength(); index++) {
                    JInstruction instr = code.getInstruction(index);
                    if (instr.getOpcode() == JInstructions.ATHROW) {
                        break;
                    } else if (isReturnInstruction(instr)) {
                        breakELoop = true;
                        break;
                    }
                }
                removeStuff(code, ei--);
            }
            if (breakELoop) break;
        }
    }
}

当查看 Java 版本然后查看移植的 C# 版本时,您会看到......干净的感觉消失了。我是否犯了一些可以使代码更短的错误?还是更好看?感谢您的帮助。

【问题讨论】:

  • 也许我老了,但我会尝试不止一种方法。您可以利用返回表达式作为伪中断来标记。
  • break label 与 GOTO 有何不同?
  • 不是,但 goto 看起来确实比仅使用布尔条件更糟。至少像这样我可以看到 continue &lt;label&gt;break&lt;label&gt; 之间的相似性。除非有办法使用 goto 执行 continue label,否则我会更改它。
  • @Cameron: GOTO 允许任意跳转,break label 只能跳转到父块的标签,标签只能附加到块上。 break label 旨在使嵌套中断更容易一些。

标签: c# java label break continue


【解决方案1】:

我猜,在 C# 中,你一开始就不会写出这么丑陋的代码。

这是您的代码重构为多个方法并使用 LINQ 和虚构的类层次结构:

IEnumerable<JCode> GetCodes(IEnumerable<JClass> classes)
{
    return from @class in classes
           from method in @class.Methods
           where method.Code != null
           select method.Code;
}

IEnumerable<Tuple<JCode, JException>> GetCandidates(IEnumerable<JCode> codes)
{
    return from code in codes
           from ex in code.ExceptionTable
           where !code.Instructions
                      .Skip(ex.Start)
                      .Take(ex.End - ex.Start + 1)
                      .Any(i => i.OpCode == New && ...)
           select Tuple.Create(code, ex);
}

然后

void RewriteMethods(IEnumerable<JClass> classes)
{
    var codes = GetCodes(classes);

    var candidates = GetCandidates(codes);

    foreach (var candidate in candidates)
    {
        var code = candidate.Item1;
        var ex = candidate.Item2;

        var instructionsToRemove = code.Instructions
                                       .Skip(ex.HandlerStart)
                                       .TakeWhile(i => i.OpCode != Return)
                                       .Where(i => i.OpCode == AThrow);

        code.RemoveAll(instructionsToRemove);
    }
}

【讨论】:

  • 对来自 java 的人要求太多,无法直接写 linq
  • 你可能是对的。但是,如果您想编写难看的 Java 代码,为什么要切换到 C# 呢?
  • 哈哈绝对看起来更干净.. 但你是对的 Pinaktin Linq 看起来很陌生,对我来说有点像 SQL:P 我可能没有能力自己编写 Linq 代码,所以我为什么要复制/粘贴这个..如果发现错误,我将不明白如何修改它。也许我可以用 RemoveAll 删除一些冗余代码。我更喜欢函数式编码。但是,嗯,这是最好的答案,我想我会标记它,它肯定会帮助很多谷歌人。
  • 迟早你会想要编写惯用的 C# 代码,而不是看起来像 Java 的杂乱代码。 LINQ 是这样做的主要原因之一早于晚
  • @SSpoke 我同意 dtb 的观点,即 Linq 会改变你的编程。即使对于长期的 C# 程序员来说,也需要一些学习。如果您不是 NGO(反微软 :)),您将开始爱上它..
【解决方案2】:

如果我们纯粹是在谈论语言规范,那么没有什么等价于 继续并在 C# 中中断。唯一看起来像的东西是 goto ,它并不是真正的替代品。我怀疑未来的 c# 版本中是否会包含这样的东西,因为 Anders Hejlsberg 似乎不喜欢任何会破坏代码一致性的东西。

没有文档说某些功能没有实现,所以我只能参考stackoverflow上此类问题的另一个答案:) C# equivalent to Java's continue <label>?

【讨论】:

    【解决方案3】:

    Break and Continue 是一种捷径

    我宁愿使用 If / Else 构造来更好地格式化并使其更清晰。您可以摆脱两种语言中的 continue 语句。你可以通过在你的 for 循环中添加一个额外的条件来为 break 做同样的事情。这也是个人喜好。

    例如

     if(code == null) continue;
    

    if(code != null)
    {
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-18
      • 2023-03-31
      • 2014-05-13
      • 1970-01-01
      • 2020-08-14
      • 1970-01-01
      相关资源
      最近更新 更多