Следующий код был подтверждением концепции сообщения, обрабатывающего стандартную программу в пакетном режиме. Сделайте я избегаю 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
}
Замените 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
}
Goto - плохая практика программирования по многим причинам. Главная из них в том, что почти никогда нет причин для этого. Кто-то опубликовал цикл do...while
, используйте его. Используйте boolean
, чтобы проверить, следует ли продолжать. Используйте цикл while. Goto - это для интерпретируемых языков и возврат к временам ассемблера (JMP
кто-нибудь?). Вы используете язык высокого уровня не просто так. Чтобы вы и все остальные не смотрели на ваш код и не терялись.
Чтобы этот ответ был в какой-то степени актуальным, я хотел бы отметить, что сочетание goto
и ошибок в скобках вызвало крупную ошибку SSL в iOS и OS X.
В этом случае я бы избегал goto и реорганизовал его.На мой взгляд, метод слишком долго читает.
Я думаю, что goto будет Чуть более интуитивно читаемым ... Но если вы ХОТИТЕ избежать этого, я думаю, все, что вам нужно сделать, это ввести код в цикл while (true)
, а затем иметь оператор break
в конце цикла для нормальной итерации. И goto
можно заменить оператором continue
.
В конце концов, вы просто научитесь читать и писать циклы и другие структуры потока управления вместо использования операторов goto
, по крайней мере, по моему опыту.
Хм, я не совсем уверен, что вы хотите выйти из блока try. Я почти уверен, что это небезопасно, хотя и не уверен в этом на 100%. Просто это выглядит не очень безопасно...
Отчасти это связано с постом Джоша К, но я пишу это здесь, поскольку в комментариях не разрешен код.
Я могу придумать хорошую причину: При обходе некоторой 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, но в данной конкретной ситуации я бы сделал это так, как я только что упомянул.
В этой ситуации так удивительно легко избавиться от 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
}
Вы могли бы рефакторить это примерно так.
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);
}
}
Заверните "HaveAnotherMessage" в метод, который принимает буфер и может вызывать себя рекурсивно. Это кажется самым простым способом исправить ситуацию.