Действительно ли этот goto выразителен?

Следующий код был подтверждением концепции сообщения, обрабатывающего стандартную программу в пакетном режиме. Сделайте я избегаю goto как эпидемия и переписывают этот код? Или Вы думаете goto выразительный путь состоял в том, чтобы сделать это?

Если Вы переписали бы, отправьте некоторый код...

var queue = new Queue<TraceItem>(this.batch);
while (this.connected)
{
    byte[] buffer = null;
    try
    {
        socket.Recv(out buffer);
    }
    catch
    {
        // ignore the exception we get when the socket is shut down from another thread
        // the connected flag will be set to false and we'll break the loop
    }

HaveAnotherMessage:
    if (buffer != null)
    {
        try
        {
            var item = TraceItemSerializer.FromBytes(buffer);
            if (item != null)
            {
                queue.Enqueue(item);

                buffer = null;
                if (queue.Count < this.batch && socket.Recv(out buffer, ZMQ.NOBLOCK))
                {
                    goto HaveAnotherMessage;
                }
            }
        }
        catch (Exception ex)
        {
            this.ReceiverPerformanceCounter.IncrementDiagnosticExceptions();
            this.tracer.TraceException(TraceEventType.Error, 0, ex);
        }
    }

    // queue processing code
}
10
задан Josh K 8 July 2010 в 02:55
поделиться

9 ответов

Замените goto на do-while или просто на цикл while, если вам не нужна функциональность "всегда запускать один раз", которая есть сейчас.

var queue = new Queue<TraceItem>(this.batch);
while (this.connected)
{
    byte[] buffer = null;
    try
    {
        socket.Recv(out buffer);
    }
    catch
    {
        // ignore the exception we get when the socket is shut down from another thread
        // the connected flag will be set to false and we'll break the loop
    }

    do {
        if (buffer != null)
        {
            try
            {
                var item = TraceItemSerializer.FromBytes(buffer);
                if (item != null)
                {
                    queue.Enqueue(item);
                    buffer = null;
                }
            }
            catch (Exception ex)
            {
                this.ReceiverPerformanceCounter.IncrementDiagnosticExceptions();
                this.tracer.TraceException(TraceEventType.Error, 0, ex);
            }
        }
    } while(queue.Count < this.batch && socket.Recv(out buffer, ZMQ.NOBLOCK))

    // queue processing code
}
19
ответ дан 3 December 2019 в 13:11
поделиться

Goto will get you into some sticky situations

Довольно точно подытоживает мои мысли о "goto."

Goto - плохая практика программирования по многим причинам. Главная из них в том, что почти никогда нет причин для этого. Кто-то опубликовал цикл do...while, используйте его. Используйте boolean, чтобы проверить, следует ли продолжать. Используйте цикл while. Goto - это для интерпретируемых языков и возврат к временам ассемблера (JMP кто-нибудь?). Вы используете язык высокого уровня не просто так. Чтобы вы и все остальные не смотрели на ваш код и не терялись.


Чтобы этот ответ был в какой-то степени актуальным, я хотел бы отметить, что сочетание goto и ошибок в скобках вызвало крупную ошибку SSL в iOS и OS X.

44
ответ дан 3 December 2019 в 13:11
поделиться

В этом случае я бы избегал goto и реорганизовал его.На мой взгляд, метод слишком долго читает.

0
ответ дан 3 December 2019 в 13:11
поделиться

Я думаю, что goto будет Чуть более интуитивно читаемым ... Но если вы ХОТИТЕ избежать этого, я думаю, все, что вам нужно сделать, это ввести код в цикл while (true) , а затем иметь оператор break в конце цикла для нормальной итерации. И goto можно заменить оператором continue .

В конце концов, вы просто научитесь читать и писать циклы и другие структуры потока управления вместо использования операторов goto , по крайней мере, по моему опыту.

5
ответ дан 3 December 2019 в 13:11
поделиться

Хм, я не совсем уверен, что вы хотите выйти из блока try. Я почти уверен, что это небезопасно, хотя и не уверен в этом на 100%. Просто это выглядит не очень безопасно...

0
ответ дан 3 December 2019 в 13:11
поделиться

Отчасти это связано с постом Джоша К, но я пишу это здесь, поскольку в комментариях не разрешен код.

Я могу придумать хорошую причину: При обходе некоторой n-мерной конструкции, чтобы найти что-то. Пример для n=3 //...

for (int i = 0; i < X; i++)
    for (int j = 0; j < Y; j++)
        for (int k = 0; k < Z; k++)
            if ( array[i][j][k] == someValue )
            {
                //DO STUFF
                goto ENDFOR; //Already found my value, let's get out
            }
ENDFOR: ;
//MORE CODE HERE...

Я знаю, что вы можете использовать "n" whiles и булевы, чтобы узнать, стоит ли продолжать... или вы можете создать функцию, которая сопоставит этот n-мерный массив с одним измерением и просто использовать один while, но я считаю, что вложенный while гораздо более читабелен.

Кстати, я не говорю, что мы все должны использовать gotos, но в данной конкретной ситуации я бы сделал это так, как я только что упомянул.

4
ответ дан 3 December 2019 в 13:11
поделиться

В этой ситуации так удивительно легко избавиться от GOTO, что это заставляет меня плакать:

var queue = new Queue<TraceItem>(this.batch);
while (this.connected)
{
    byte[] buffer = null;
    try
    {
        socket.Recv(out buffer);
    }
    catch
    {
        // ignore the exception we get when the socket is shut down from another thread
        // the connected flag will be set to false and we'll break the loop
    }
    bool hasAnotherMessage = true
    while(hasAnotherMessage)
    {
        hasAnotherMessage = false;
        if (buffer != null)
        {
            try
            {
                var item = TraceItemSerializer.FromBytes(buffer);
                if (item != null)
                {
                    queue.Enqueue(item);

                    buffer = null;
                    if (queue.Count < this.batch && socket.Recv(out buffer, ZMQ.NOBLOCK))
                    {
                        hasAnotherMessage = true;
                    }
                }
            }
            catch (Exception ex)
            {
                this.ReceiverPerformanceCounter.IncrementDiagnosticExceptions();
                this.tracer.TraceException(TraceEventType.Error, 0, ex);
            }
        }
    }
    // queue processing code
}
18
ответ дан 3 December 2019 в 13:11
поделиться

Вы могли бы рефакторить это примерно так.

while (queue.Count < this.batch && buffer != null)
{
    try
    {
        var item = TraceItemSerializer.FromBytes(buffer);
        buffer = null;
        if (item != null)
        {
            queue.Enqueue(item);
            socket.Recv(out buffer, ZMQ.NOBLOCK)
        }
    }
    catch (Exception ex)
    {
        this.ReceiverPerformanceCounter.IncrementDiagnosticExceptions();
        this.tracer.TraceException(TraceEventType.Error, 0, ex);
    }
}
3
ответ дан 3 December 2019 в 13:11
поделиться

Заверните "HaveAnotherMessage" в метод, который принимает буфер и может вызывать себя рекурсивно. Это кажется самым простым способом исправить ситуацию.

0
ответ дан 3 December 2019 в 13:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: