С# 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

Это общее требование при написании критически важного кода. Там, чтобы предотвратить случайное присвоение, вы должны сделать чек. На языке, подобном С#, компилятор будет предупреждать вас об этом, поэтому он не является необходимым, но для многих программистов это остается привычкой.