Синтаксически я вижу, что они циклично выполняются неограниченно долго, пока оператор завершения не достигнут, но они компилируются в то же самое? Для немного быстрее, потому что это не имеет условия проверить? Кроме удобочитаемости кода, существует ли даже различие?
Учитывая этот ввод:
private static void ForLoop()
{
int n = 0;
for (; ; )
{
Console.WriteLine(n++);
}
}
private static void WhileLoop()
{
int n = 0;
while (true)
{
Console.WriteLine(n++);
}
}
... вы получите следующий результат:
.method private hidebysig static void ForLoop() cil managed
{
// Code size 14 (0xe)
.maxstack 3
.locals init ([0] int32 n)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: dup
IL_0004: ldc.i4.1
IL_0005: add
IL_0006: stloc.0
IL_0007: call void [mscorlib]System.Console::WriteLine(int32)
IL_000c: br.s IL_0002
} // end of method Program::ForLoop
.method private hidebysig static void WhileLoop() cil managed
{
// Code size 14 (0xe)
.maxstack 3
.locals init ([0] int32 n)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: dup
IL_0004: ldc.i4.1
IL_0005: add
IL_0006: stloc.0
IL_0007: call void [mscorlib]System.Console::WriteLine(int32)
IL_000c: br.s IL_0002
} // end of method Program::WhileLoop
Замечательно похожий, я бы сказал (идентичный, даже).
В современных компиляторах абсолютно ничего.
Исторически, однако, для (;;)
было реализовано как одиночный переход, в то время как while (true)
также имел проверку на истинность.
Я предпочитаю , в то время как (правда)
, поскольку это дает более ясное представление о том, что я делаю.
Они компилируются в одно и то же. Вы можете написать тестовое приложение, реализующее оба метода, а затем использовать ILDASM, чтобы убедиться, что они идентичны IL.
Как упоминалось другими, для любого современного компилятора это не должно иметь абсолютно никакого значения.
Я провел краткий тест на своем компьютере, рассчитав пару операций с использованием того или другого, и они всегда занимали примерно одно и то же время. Конечно, из-за того, что работают другие процессы, эти тесты не на 100% точны, но если есть разница в скорости (ее не должно быть), то она микроскопическая.
Отладочная сборка соответствует while(true). Используйте reflector и вы сможете увидеть результаты.
static void Main(string[] args)
{
ExecuteWhile();
ExecuteFor();
}
private static void ExecuteFor()
{
for (; ; )
{
Console.WriteLine("for");
string val = Console.ReadLine();
if (string.IsNullOrEmpty(val))
{
Console.WriteLine("Exit for.");
break;
}
}
}
private static void ExecuteWhile()
{
while (true)
{
Console.WriteLine("while");
string val = Console.ReadLine();
if (string.IsNullOrEmpty(val))
{
Console.WriteLine("Exit while.");
break;
}
}
}
Проверка метода ExecuteFor
в Reflector.
private static void ExecuteFor()
{
while (true)
{
Console.WriteLine("for");
if (string.IsNullOrEmpty(Console.ReadLine()))
{
Console.WriteLine("Exit for.");
return;
}
}
}
Оптимизированная версия того же кода дает другие результаты для ExecuteFor
private static void ExecuteFor()
{
do
{
Console.WriteLine("for");
}
while (!string.IsNullOrEmpty(Console.ReadLine()));
Console.WriteLine("Exit for.");
}
Для наглядности вот оптимизированный ExecuteWhile
...
private static void ExecuteWhile()
{
do
{
Console.WriteLine("while");
}
while (!string.IsNullOrEmpty(Console.ReadLine()));
Console.WriteLine("Exit while.");
}
Я не проверял выходной код, но никакой разницы быть не должно. Любой достойный компилятор выполнит достаточно простую оптимизацию цикла, чтобы убедиться, что условие является постоянным выражением, и, следовательно, не нужно проверять каждую итерацию.
Если один из них быстрее, чем другой, разработчикам компилятора C # нужно что-то «объяснить» им ...
Если можно, я бы посоветовал вам взглянуть на несколько другой вопрос. Если вы достаточно часто пользуетесь одним из этих способов, вероятно, вы плохо структурируете свой код. Хотя есть такие вещи, как встроенные системы, которые действительно работают вечно, циклы в большинстве нормального кода - нет. Написание цикла, который утверждает, что запускается вечно, обычно означает, что вы скрыли условие выхода для цикла где-то внутри, с каким-то другим потоком управления (например, if (независимо) break;
) как действительный выход из цикла.
Этого можно и обычно следует избегать. Хотя бывают ситуации, когда операторы break
имеют смысл, они обычно предназначены для обработки необычных ситуаций, а не для написания цикла, который говорит одно, но делает другое (например, говорит «запускать вечно», но на самом деле делает » работать до тех пор, пока не будет выполнено условие ").