2015-01-31 7 views
9

Для моего экзамена по программированию мне пришлось защищать код, который я написал. Одна из линий:Выполняется ли проверка того, является ли строка пустой или пустой?

if(app.Logourl == "" || app.Logourl == null) 

Он спросил меня, существует ли разница между нулем и пустой строкой. Я сказал ему, что разница в том, что null означает, что он не указывает ни на что, поэтому он не создается, но пустая строка.

После экзамена я подошел к нему и спросил его, правильно ли я, так как я увидел смешной взгляд на его лице. Он сказал мне, что это правда, что они разные, но порядок, в котором я проверил значения, был неправильным.

Теперь через несколько дней я верю, что нет ничего плохого в заказе. Я прав?

TL; DR

является

if(app.Logourl == "" || app.Logourl == null) 

эквивалентно

if(app.Logourl == null || app.Logourl == "") 
+4

Вместо этого использовать 'String.IsNullOrEmpty';) –

+1

Farhad прав, конечно. Кроме того, для микро-микро-оптимизации, условие, которое, по вашему мнению, чаще всего будет истинным во-первых, чтобы оценка короткого замыкания пропустила последнюю проверку в большем количестве случаев. –

+1

Как указывали другие, это все равно в вашем фактическом случае. Тем не менее, я бы предложил пойти с маршрутом, предложенным вашим учителем, и привыкнуть к тому, чтобы всегда проверять «нуль». Во многих практических случаях, как указано в ответах, оно * будет * иметь значение и начиная с проверки «null» просто уменьшит ваши ошибки в долгосрочной перспективе. Везде, где среда предлагает специализированную функцию, такую ​​как 'IsNullOrEmpty()', используйте это, а не, конечно, но вы будете использовать один и тот же шаблон во многих других случаях, когда вам нужно вручную закодировать проверки. –

ответ

14

Это нормально, как вы сделали это, потому что перегрузка == для System.String вызовов String.Equals, что позволяет null с.

Это не является универсальным, однако: если вы хотите, чтобы проверить длину строки вместо использования == "", ваш первый фрагмент кода будет в беде:

if(app.Logourl.Length == 0 || app.Logourl == null) // <<== Wrong! 

, а второй один будет в порядке:

if(app.Logourl == null || app.Logourl.Length == 0) // <<== Correct 

причиной этого является короткое замыкание в оценке || и && операторов: как только они знают, что результат (true для ||, false для &&), они прекращают оценку. Во втором фрагменте выше, если app.Logourl - null, вторая половина выражения будет проигнорирована, поэтому app.Logourl.Length не будет выбрасывать исключение с нулевой ссылкой.

Примечание: В знак признания проверок, как это происходит повсюду, библиотека C# класс offers a convenience method for doing this check:

if (string.IsNullOrEmpty(app.Logourl)) { 
    ... 
} 
+2

В ваш первый оператор я могу добавить комментарий, что все перегрузки оператора '==', определенные спецификацией C#, включая отмененные операторы по значениям nullables, и все дополнительные перегрузки '==', определенные BCL, позволят (т.е. не бросать) один или оба операнда для 'null'. Пользователь может ввести перегрузку '==', которая бросает, но я предполагаю, что это будет разорвать «контракт» на то, как «==» должен быть реализован. –

1

Нет, это не имеет значения (в вашем случае).

Одна вещь, чтобы знать, однако, является то, что логические операторы && и || короткого замыкания, что означает, если у вас есть a || b и a является true, то b не оценивается.

Например,

app.Logourl == null || app.Logourl == "" 

Если app.Logourl является null, то app.Logourl == "" никогда даже не оценивали.

В вашем случае нет реальной разницы, проверяете ли вы один или другой. первый или второй. Если бы проверки были разными, это могло бы иметь значение.

Например,

app.Logourl == null || app.Logourl.Equals("") 

Если вы сделали другой заказ, вы получите исключение, если app.Logourl является null, так как вы не можете вызывать функции-члены нулевых ссылок.


Хотя я бы использовал String.IsNullOrEmpty(app.Logourl), который является стандартной LIB.

0

, когда я уверен, что мой объект является string я всегда предпочитаю следующее:

if (string.IsNullOrEmpty(yourString)) 
    { 
     // this string is null or empty 
    } 

или это:

if (string.IsNullOrWhiteSpace(yourString)) 
    { 
     // this string is null or empty (or got only a space) 
    } 
+1

Обратите внимание, что если вы * не * уверены, что это строка или нет, то есть, если объявленный тип (тип времени компиляции) является «объектом» или интерфейсом, который реализует 'string', говоря **' obj == " «** должно давать предупреждение о времени компиляции. Это опасно, потому что он проверяет ссылочное равенство. Иногда бывает несколько экземпляров 'string', которые пусты. –

1

Это всего лишь комментарий.

В обычных ситуациях это не имеет значения. Но могут быть побочные эффекты. Вот простой пример, чтобы узнать из:

static class Program 
{ 
    static string Logourl 
    { 
     get 
     { 
      Console.WriteLine("getter runs"); 
      return null; 
     } 
    } 

    static void Main() 
    { 
     if (Logourl == "" || Logourl == null) 
     { 
     } 
    } 
} 

Эта программа будет написать:

getter runs 
getter runs

Если поменять порядок проверок, getter runs будет печатать только один раз. Если вы измените свойство на return "";, это будет наоборот.

Использование string.IsNullOrEmpry(Logurl) будет всегда получать собственность ровно один раз, конечно.

2
private static bool IsNullOrEmpty(string s) 
    { 
     return s == null || s == ""; 

     /* 
     Lets look behind the scenes here: 
     ================================= 
     IL_0000: ldarg.0 => load s on the evaluation stack 
     IL_0001: brfalse.s IL_000f => GoTo label 'IL_000f' if loaded argument is null 

     IL_0003: ldarg.0 => load s on the evaluation stack 
     IL_0004: ldstr "" => load constant string "" to the evaluation stack 
     IL_0009: call bool [mscorlib]System.String::op_Equality(string, string) 
           => Call String.Equality(string,string) with s and "" 
           loaded to the evalutation stack 
           that will pop the two values compare them for equality and load the result. 
           to the evaluation stack.          

     IL_000e: ret => Return to the caller with equlity result on the evauation stack. 

     IL_000f: ldc.i4.1 => Load constant value 1(4 byte which will represent "True") to the evaluation stack 
          and return to the caller.In our flow it's the case when s is null. 
     IL_0010: ret 

     In Summary: 
     =========== 
     1.) IL instructions total code size 17 bytes. 
     2.) Best case scenario execution path => 2 IL instructions. 
     3.) Worst case scenario execution pat => 8 IL instructions. 

     */ 
    } 

    private static bool IsEmptyOrNull(string s) 
    { 
     return s == "" || s == null; 

     /* 
     Lets look behind the scenes here: 
     ================================= 
     IL_0000: ldarg.0 => load s on the evaluation stack 
     IL_0001: ldstr "" => load constant string "" to the evaluation stack 
     IL_0006: call bool [mscorlib]System.String::op_Equality(string, string) 
     IL_000b: brtrue.s IL_0012 

     IL_000d: ldarg.0 => load s on the evaluation stack 
     IL_000e: ldnull => load constant null on the evaluation stack 
     IL_000f: ceq => Pop two loaded values compare and push the result back on the evaluation stack 
     IL_0011: ret 

     IL_0012: ldc.i4.1 => Load constant value 1(4 byte which will represent "True") to the evaluation stack 
          and return to the caller.In our flow it's the case when s is null. 
     IL_0013: ret 

      In Summary: 
     =========== 
     1.) IL instructions total code size 20 bytes. 
     2.) Best case scenario execution path => 6 IL instructions. 
     3.) Worst case scenario execution path => 10 IL instructions. 
    */ 

    } 

Вывод:

Судя только IL излучаемого код "если (app.Logourl == "" || app.Logourl == NULL)" является "microptimization" лучше производительность мудрым:)

Смежные вопросы