Как переписать Java [продолжить ‹метку› и разорвать ‹метку›] на C#?

На Java это написано так... когда я портировал этот код... понял, что нет таких вещей, как break <label> и continue <label>.

Я знаю, что эти команды не были включены, потому что ДОЛЖЕН быть более чистый способ сделать это при использовании goto с командой.

Но в итоге я использовал... приведенный ниже код С#, чтобы переписать его чище?

Код 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#... ощущение чистоты уходит. Допустил ли я какие-то ошибки, из-за которых код стал короче? или красивее? Спасибо за помощь.


person SSpoke    schedule 20.07.2011    source источник
comment
Может быть, я старею, но я бы использовал более одного метода. Затем вы можете использовать выражение возврата как псевдоразрыв для метки.   -  person Adam Gent    schedule 20.07.2011
comment
Чем break label отличается от GOTO?   -  person Cameron    schedule 20.07.2011
comment
это не так, но goto выглядит хуже, чем просто использование логических условий.. по крайней мере, так я вижу сходство между continue <label> и break<label>. Если нет способа сделать continue label с помощью goto, я его изменю.   -  person SSpoke    schedule 20.07.2011
comment
@Cameron: GOTO допускает произвольные переходы, break label может переходить только к меткам родительских блоков, а метки можно прикреплять только к блокам. break label предназначен для облегчения вложенного взлома.   -  person Mark Elliot    schedule 20.07.2011


Ответы (3)


Думаю, на 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);
    }
}
person dtb    schedule 20.07.2011
comment
слишком многого просить от кого-то, пришедшего из java, чтобы сразу написать linq - person Pinakin Shah; 20.07.2011
comment
Возможно Вы правы. Но зачем переключаться на C#, если вы хотите писать уродливый Java-код? - person dtb; 20.07.2011
comment
Ха-ха, определенно выглядит чище... но вы правы. Pinaktin Linq выглядит чужеродным, для меня это немного похоже на SQL :P У меня, вероятно, не будет возможности написать код Linq самостоятельно, так почему я должен просто копировать/вставлять это... я не буду' не понимаю, как изменить его, если ошибка когда-либо будет найдена. Возможно, вместо этого я смогу удалить часть избыточного кода с помощью RemoveAll. Мне больше нравится функциональное кодирование. Но это лучший ответ, я думаю, я отмечу его, это наверняка поможет многим гуглерам. - person SSpoke; 20.07.2011
comment
Рано или поздно вам захочется писать идиоматический код C#, а не беспорядочный код, похожий на Java. LINQ — одна из главных причин сделать это намного раньше, чем позже. - person dtb; 20.07.2011
comment
@SSpoke Я согласен с dtb в том, что Linq изменит ваше программирование. Даже давним программистам на C# потребовалось некоторое обучение. Если вы не неправительственная организация (анти-Майкрософт :)), вам это начнет нравиться.. - person Pinakin Shah; 20.07.2011

Если мы говорим исключительно о спецификации языка, то в C# нет ничего эквивалентного continue и break. Единственное, что похоже на это, это goto, который на самом деле не является заменой. Я сомневаюсь, что такая вещь будет включена в будущие версии C #, поскольку Андерс Хейлсберг, похоже, не любит все, что может нарушить связность кода.

Нет документа, в котором говорится, что некоторые функции не реализованы, поэтому я могу только отослать вас к другому ответу на такой вопрос в stackoverflow :) С# эквивалентно продолжению ‹label› в Java?

person Nikola Radosavljević    schedule 20.07.2011

Перерыв и продолжение — это своего рода ярлыки

Я бы предпочел использовать конструкцию If / Else, чтобы лучше отформатировать и сделать ее чище. Вы можете избавиться от операторов continue на обоих языках. Вы можете сделать то же самое для break, добавив дополнительное условие в цикл for. Опять же, это личные предпочтения.

e.g.

 if(code == null) continue;

to

if(code != null)
{

}
person Pinakin Shah    schedule 20.07.2011