С# if. внутренние работы Q
Я только что нашел этот фрагмент кода в коде Exchange 2010, и мне было интересно, знает ли кто-нибудь, почему программист сделал это так. Я никогда не видел оператора If, отформатированного таким образом. Кажется, что назад, должно быть веская причина для этого?
if (true == MsgItem.HasAttachments)
{
// Code
}
Я предполагаю, что он может иметь некоторую оптимизацию по различным другим способам кодирования одной и той же вещи;
if (MsgItem.HasAttachments)
{
// Code
}
или
if (MsgItem.HasAttachments == true)
{
// Code
}
Это не большая проблема. Мне просто интересно.
Спасибо,
Mike
ОБНОВЛЕНИЕ: Спасибо за все интересные моменты. Резюме, похоже, сводится к устаревшим стандартам кодирования.
Ответы
Ответ 1
Это привычка с левой стороны от C или С++, где вы можете случайно:
if (i = 1) {
}
Это случайно присваивает 1
i
вместо сравнения.
Реверсирование порядка в проверке предотвращает эту распространенную ошибку.
if (1 = i) {
}
Это не скомпилируется, и легко видеть, что вы ошибочно набрали =
вместо ==
.
Это все еще актуально для bools
в С#, потому что значение присваивания - это назначенное значение.
Therefor:
if (SomeBoolVar = true) {
}
Всегда будет верно, потому что вы храните true
в SomeBoolVar
, который оценивается как true
. Небольшая ошибка, которую трудно отследить.
Ответ 2
Программисты С++ и C иногда помещают константы во избежание случайной записи
if (variable = constant)
который выполнил бы назначение.
В частности, явно для булевых сравнений, предполагая, что HasAttachments
доступен для записи, этот оператор будет компилировать и запускать без предупреждений 1 но не иметь предполагаемого поведения в С#:
if (MsgItem.HasAttachments = true)
Для небулевых выражений это обычно не проблема в С#, поскольку условие оператора if
должно быть неявно конвертируемым в bool
... и для булевых выражений ваша средняя форма является предпочтительной в любом случае
if (MsgItem.HasAttachments)
Я был бы поражен, если бы у него было какое-либо влияние на производительность - и, вероятно, не повлияло на сгенерированный IL, чтобы начать с.
1 Упс - компилятор MS С# действительно предупреждает об этом:
warning CS0665: Назначение в условном выражении всегда постоянное; вы хотели использовать == вместо =?
Я не пробовал это в Mono, хотя; который может или не может дать предупреждение. Это, безусловно, действительный код С#.
Ответ 3
Они называются "Условия Yoda" - оригинальная идея состоит в том, что если вы случайно наберете один =
, компиляция завершится неудачно, потому что постоянное значение включено с левой стороны.
Ответ 4
Потому что программист - клоун:-) Вся суть булевых условий заключается в том, что вы называете их такими, чтобы они имели смысл в качестве булевых:
if (MsgItem.HasAttachments)
и это явно делает это, я не знаю, почему кодер выстрелил себе в ногу, проверив равенство против true
.
Потому что, со всей серьезностью, true == MsgItem.HasAttachments
является просто еще одним булевым, поэтому, где вы остановились?
if (true == MsgItem.HasAttachments)
if (true == (true == MsgItem.HasAttachments))
if (true == (true == (true == MsgItem.HasAttachments)))
: : :
И так далее, до бесконечности.
Весь трюк использования константы во-первых, чтобы избежать проблемы случайного использования назначения =
вместо равенства ==
, здесь не должно быть проблемой, так как вы не должны проверять логическое значение на true
или false
. Вы должны использовать один из:
if (cond)
if (!cond)
Ответ 5
Существует прекрасная причина писать if (true == myvar)
: переменная (или выражение) может не быть логическим выражением - это может быть bool?
. Тогда выражение будет эквивалентно if(myvar ?? false)
- и я предпочитаю этот второй синтаксис, так как сразу же очевидно, что вы имеете дело с нулевым значением. Технически возможно, что используется пользовательский оператор ==
(потенциально в сочетании с неявным преобразованием типов), но это маловероятно, поскольку он делает что-то вроде этого, как правило, неодобрен и не является практичным или удобным.
Помещение константы сначала, как многие другие отметили, может уменьшить случайные ошибки - лично, я не думаю, что эти ошибки происходят достаточно часто, чтобы иметь значение, но это не может нанести вред.
Скорее всего, однако, оригинальный автор был немного смущен в тот момент, когда он написал этот код.
Ответ 6
В mono все они генерируют один и тот же IL (ldloc.0; brfalse <LOC>
):
Источник:
using System;
class Foo
{
static void Main()
{
bool bar = Console.ReadLine() == "bar";
if (bar)
{
Console.WriteLine("bar");
}
if (true == bar)
{
Console.WriteLine("true == bar");
}
if (bar == true)
{
Console.WriteLine("bar == true");
}
}
}
IL:
// snip...
IL_000a: call bool string::op_Equality(string, string)
IL_000f: stloc.0
IL_0010: ldloc.0
IL_0011: brfalse IL_0020
IL_0016: ldstr "bar"
IL_001b: call void class [mscorlib]System.Console::WriteLine(string)
IL_0020: ldloc.0
IL_0021: brfalse IL_0030
IL_0026: ldstr "true == bar"
IL_002b: call void class [mscorlib]System.Console::WriteLine(string)
IL_0030: ldloc.0
IL_0031: brfalse IL_0040
// snip...
Лично, это заставляет меня гаснуть, когда люди делают if (SomePredicate() == true)
. Если он фактически не возвращает объект с перегруженным оператором ==
, сравнение с true
совершенно не нужно. Зачем останавливаться на одном сравнении?
// make extra sure SomePredicate returns true
if ((SomePredicate() == true) == true)
{
// ...
}
Ответ 7
возможно, оператор ==
был перегружен, а MsgItem.HasAttachments
имеет больше информации, а просто bool
? Я не знаю. Просто идея.
Ответ 8
Это общее требование при написании критически важного кода. Там, чтобы предотвратить случайное присвоение, вы должны сделать чек. На языке, подобном С#, компилятор будет предупреждать вас об этом, поэтому он не является необходимым, но для многих программистов это остается привычкой.