При равном сравнении буквального значения имеет значение порядок операндов?

Я привык писать код как (просто пример)

Request.QueryString["xxxx"] != null

Недавно кто-то сказал, что

null != Request.QueryString["xxxx"]

дает лучшую производительность.

Мне любопытно узнать, действительно ли это приносит какую-то разницу или нет, и если да, то как?

Примечание ~ Выше приведен только пример. Говоря в общем

Будь то

Constant [Operator] Actual Value (e.g. 1 == Convert.ToInt32(textbox1.text))

лучше, чем

Actual Value [Operator] Constant (e.g. Convert.ToInt32(textbox1.text) == 1)

Спасибо

Ответы на вопрос(4)

What

используемый для языков со многими неявными преобразованиями типов (дружелюбный по имени Йода из персонажа Звездных войн из-за егоOSV порядок слов). Иногда это даже предписывается и требуется руководящими принципами проекта для предотвращения каких-либо ошибок, вытекающих из опечаток. Разные языки имеют разныеvariations и расширения этого стиля, но я ограничу этот ответ C и C #.

Why Yes

Например, в C вы можете написать:

int a = CalculateValue();
if (a = CalculateAnotherValue()) {
    /* Do something */
}

Этот код будет назначенa значение, возвращаемое изCalculateValue() затем оно перезапишет значение с результатомCalculateAnotherValue() и если он не равен нулю, тогда он выполнит код. Возможно, это не то, что намеревалось сделать, а назначение вif выражение это ошибка. Из вашего примера сNULL тогда вы можете иметь:

if (pBuffer = NULL)

Опять же, вероятно, это не то, что вам нужно (и это довольно распространенная ошибка), вы назначите NULL для указателя, и условие всегда будет ложным. Если вы напишите:

if (NULL = pBuffer)

Он не скомпилируется (потому что вы не можете присвоить значение литералу), и вы получите ошибку во время компиляции.

Этот вид проверок времени компиляции - не единственная причина для использования этого стиля кодирования, посмотрите этот код C # (очень распространенный):

if (text != null && text.Equals("something", StringComparison.InvariantCulture)
    DoSomething();

Можно заключить договор на:

if ("something".Equals(text, StringComparison.InvariantCulture))
    DoSomething();
Why No

В C #usually это не имеет значения. Это практикаinherited из C / C ++. Потому что в C # выражения автоматически не преобразуются вbool затем следующий код не скомпилируется:

if (Request.QueryString["PartnerID"] = null)

Тогда эта практика бесполезна в C # (за исключением того, что @IlianPinzon указал в комментариях), ничего о производительности она не использовала только для того, чтобы избежать подобных ошибок.

О последнем примере вWhy yes В разделе проблема читаемости, чтобы написать"something".Equals(text) все равно, что сказать «счастлив ли парень» вместо "если парень счастлив".

Performance

Начиная с этих функций:

static bool TestRight(object value)
{ return value == null; }

static bool TestLeft(object value)
{ return null == value; }

Они производят следующие IL:

.maxstack 2
.locals init ([0] bool CS$1$0000)
L_0000: nop 
L_0001: ldnull 
L_0002: ldarg.0 
L_0003: ceq 
L_0005: stloc.0 
L_0006: br.s L_0008
L_0008: ldloc.0 
L_0009: ret 

Единственное различие заключается в строках L_0001 и L_0002, они просто меняются местами, но порядок их операндов не меняет поведениеceq, Даже если вы переопределитеEquals() Метод JIT-компилятор выдаст одинаковый ассемблерный код для обоих выражений (потому что сравнение всегда будет выполнятьсяEquals(), null являетсяtypeless).

Ситуация может быть более сложной, если сравнение включает в себя определяемый пользователем модуль сравнения равенства, в этом случае нет правила, и оно будет зависеть от эффективногоop_Equals реализация. Например это== реализация:

public static bool operator==(MyType lhs, MyType rhs)
{
    if (Object.ReferenceEquals(lhs, rhs))
        return true;

    if (Object.ReferenceEquals(lhs, null))
        return false;

    return lhs.Equals(rhs);
}

В этом случае, если первый операндnull выполнение будет немного быстрее (потому чтоMyType.Equals() не будет даже вызван), но это увеличение производительности очень мало: вы экономите одно сравнение, несколько переходов и вызов виртуальной функции. Более того, вы можете переписать функцию так, чтобы она была быстрее в противоположном случае (если вы действительно в этом заинтересованы).

Здесь небольшой тест, гдеMyType.Equals(object) просто возвращаетсяtrue для любого неnull параметр. Тест будет зацикленInt32.MaxValue раз:

Operation       Total time (ms)
lhs == null               10521
null == lhs                2346

Кажется, «оптимизирован» версия, которая позволяет избежать ненужного вызоваEquals() в пять раз быстрее, но обратите внимание, что число циклов очень велико и фактическая реализацияEquals() пуст, истинная реализация уменьшит относительные накладные расходы при вызове функции (и, вероятно, у вас будет что-то еще, кроме этогоmicro-optimization сделать). Для системных классов вы не можете полагаться на эту информацию, напримерString.Equals() всегда будет вызываться операторами (независимо от порядка), но вы не можете предполагать, что один путь кода быстрее, и этот факт не изменится в будущих версиях платформы (или для разных архитектур ЦП).

 30 мая 2012 г., 09:04
@ Adriano: есть один сценарий, где вы все равно можете его укусить в C #. Попробуйте заменитьint сbool, Но да, условия Yoda вышли из моды в C #.
 30 мая 2012 г., 09:08
@ Маттен Я добавил несколько примеров.
 30 мая 2012 г., 16:20
+1 за замечание о перегруженных пользователем операторах сравнения.
 30 мая 2012 г., 09:07
@ IlianPinzon Вы правы, с bool это имеет смысл, но ... мне это очень не понравилось из-за читабельности (я знаю, что мне нравится), что я готов заплатить цену :)
 30 мая 2012 г., 09:02
Мне любопытно, я слышал об этом, но я не знаком с C / C ++. Почему часто было иметь постоянную на левой стороне?

Это вопрос стиля. Кто-то предпочитает писать

if (N == var) ...

только потому, что если вы пропустили один= (общий случай для начинающих)

if (N = var)

гдеN постоянно, компилятор выдаст ошибку.

В случае

if (var = N)

он может дать вам предупреждение, а может и нет (зависит от компилятора и флагов). Так что иногда бывает достаточно сложно определить, в чем проблема.

Производительность обоих вариантов одинакова. Выберите свой стиль и следуйте ему.

Constant [Operator] Actual Value известен какЙода Условия потому что это как & quot; если это синий & # x2013; это небо & quot; или & quot; если оно высокое & # x2013; это мужчина. & quot;

Использование этого стиля условий было популярно на C / C ++, где вы могли присвоить значение переменной при вводе= вместо==, В C # нет смысла использовать условия Yoda.

Также я сомневаюсь, что у него есть лучшие показатели. Даже если он имеет некоторое преимущество в производительности, он будет очень маленьким. Соответствие меньше, чем недостатки читабельности.

Решение Вопроса

это не совсем так. Операторы сравнения должны оценивать обе их стороны, поэтому нет смысла размещать константы слева. Но их расположение слева (так называемый стиль Yoda) уменьшает количество ошибок кодирования в языках, где вам разрешено использовать оператор присваивания внутри условного выражения, и вы непреднамеренно ошибочно набрали оператор сравнения== как единый=:

// What you intended to write
if (a == 6) ...
// What you wrote instead
if (a = 6) ... // --> always true as the value of a is changed to 6
// What if Yoda style is used
if (6 = a) ... // --> compile time error
 27 нояб. 2014 г., 15:05
Это не единственная причина, по сравнению с нулем. В некоторых случаях это может помешать перегруженному оператору == попасть в бесконечный цикл при неправильном кодировании, особенно если класс принадлежит сторонней библиотеке, которой вы не можете доверять на 100%.

Ваш ответ на вопрос