Допустим, мы имеем:
public void TestIndex1(int index)
{
if(index < 0 || index >= _size)
ThrowHelper.ThrowArgumentOutOfRangeException();
}
public void TestIndex2(int index)
{
if((uint)index >= (uint)_size)
ThrowHelper.ThrowArgumentOutOfRangeException();
}
Давайте компилировать их и посмотреть на ILSpy:
.method public hidebysig
instance void TestIndex1 (
int32 index
) cil managed
{
IL_0000: ldarg.1
IL_0001: ldc.i4.0
IL_0002: blt.s IL_000d
IL_0004: ldarg.1
IL_0005: ldarg.0
IL_0006: ldfld int32 TempTest.TestClass::_size
IL_000b: bge.s IL_0012
IL_000d: call void TempTest.ThrowHelper::ThrowArgumentOutOfRangeException()
IL_0012: ret
}
.method public hidebysig
instance void TestIndex2 (
int32 index
) cil managed
{
IL_0000: ldarg.1
IL_0001: ldarg.0
IL_0002: ldfld int32 TempTest.TestClass::_size
IL_0007: blt.un.s IL_000e
IL_0009: call void TempTest.ThrowHelper::ThrowArgumentOutOfRangeException()
IL_000e: ret
}
Легко видеть, что второй имеет меньше кода, с одной меньше отрасли.
Действительно, нет броска на все, что есть выбор, следует ли использовать blt.s
и bge.s
или использовать blt.s.un
, где последний обрабатывает целые числа, переданные в качестве знака в то время как бывшие трактует их как знаковые.
(Примечание для тех, кто не знаком с КСС, так как это C# вопрос с КСС ответ, bge.s
, blt.s
и blt.s.un
являются «короткие» версии bge
, blt
и blt.un
соответственно. blt
выскакивает два значения из стека и ветви, если первая меньше второй, рассматривая их как подписанные значения, тогда как blt.un
извлекает два значения стека и ветвей, если первое меньше второго, рассматривая их как значения без знака).
Это совершенно микроопт, но есть моменты, когда стоит делать микроопт. Рассмотрим далее, что с остальной частью кода в теле метода это может означать разницу между тем, что попадает внутрь пределов колебаний для вложения или нет, и если они беспокоятся о том, чтобы иметь помощника для исключения исключений из диапазона, они вероятно, попытка обеспечить inlining происходит, если это вообще возможно, и дополнительные 4 байта могут иметь значение.
Действительно, вполне вероятно, что разница в разветвлении будет гораздо более сложной, чем сокращение одной ветви. Не так много раз, когда вы идете на своем пути, чтобы обеспечить, что инлайнкация происходит, стоит того, но основным методом такого интенсивного использования, как List<T>
, несомненно, будет один из них.
Любопытство в этом случае легко выполняется с помощью нескольких строк кода. Попробуй это. –
@SamAxe тест будет только подтверждать, что касты быстрее (если они есть), а не объяснять почему. – enzi
Заглянув в получившийся ИЛ, ответит на вопрос почему. –