Search code examples
c#javalabelbreakcontinue

How to rewrite Java [continue <label> and break <label>] in C#?


In Java it's written like this.. when I was porting this code... realizied there is no such thing as break <label> and continue <label>.

I know those commands were not included because there HAS to be a cleaner way of doing this when using a goto with a command..

But I ended up using.. the C# code below any way to rewrite it cleaner?

Java Code

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# Code.

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;
        }
    }
}

You can see when looking at the Java version then looking at the ported C# version.. the clean feeling goes away. Did I make some mistakes that can make the code shorter? or nicer looking? thanks for the help.


Solution

  • I guess, in C# you would never write such ugly code in the first place.

    Here's your code refactored into multiple methods and to use LINQ with a fictional class hierarchy:

    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);
    }
    

    and then

    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);
        }
    }