it-roy-ru.com

Что предпочтительнее: Nullable <T> .HasValue или Nullable <T>! = Null?

Я всегда использовал Nullable<>.HasValue, потому что мне понравилась семантика. Однако недавно я работал над существующей кодовой базой другого человека, где вместо этого они использовали исключительно Nullable<> != null.

Есть ли причина использовать один над другим или это просто предпочтение?

  1. int? a;
    if (a.HasValue)
        // ...
    

vs.

  1. int? b;
    if (b != null)
        // ...
    
383
lc.

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

421
Rex M

Я предпочитаю (a != null), чтобы синтаксис соответствовал ссылочным типам.

41
cbp

Я провел некоторое исследование по этому вопросу, используя различные методы для присвоения значений обнуляемому int. Вот что случилось, когда я делал разные вещи. Следует уточнить, что происходит. Имейте в виду: Nullable<something> или сокращение something? - это структура, для которой компилятор, кажется, выполняет большую работу, чтобы позволить нам использовать с нулем, как если бы это был класс.
Как вы увидите ниже, SomeNullable == null и SomeNullable.HasValue всегда будут возвращать ожидаемое значение true или false. Хотя это и не показано ниже, SomeNullable == 3 также допустим (при условии, что SomeNullable является int?).
Хотя SomeNullable.Value возвращает нам ошибку времени выполнения, если мы присвоили nullSomeNullable. Фактически это единственный случай, когда обнуляемые значения могут вызвать у нас проблему благодаря комбинации перегруженных операторов, перегруженного метода object.Equals(obj) и оптимизации компилятора и обезьяньего бизнеса.

Вот описание некоторого кода, который я запустил, и какой вывод он произвел в метках:

int? val = null;
lbl_Val.Text = val.ToString(); //Produced an empty string.
lbl_ValVal.Text = val.Value.ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValEqNull.Text = (val == null).ToString(); //Produced "True" (without the quotes)
lbl_ValNEqNull.Text = (val != null).ToString(); //Produced "False"
lbl_ValHasVal.Text = val.HasValue.ToString(); //Produced "False"
lbl_NValHasVal.Text = (!(val.HasValue)).ToString(); //Produced "True"
lbl_ValValEqNull.Text = (val.Value == null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValValNEqNull.Text = (val.Value != null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")

Хорошо, давайте попробуем следующий метод инициализации:

int? val = new int?();
lbl_Val.Text = val.ToString(); //Produced an empty string.
lbl_ValVal.Text = val.Value.ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValEqNull.Text = (val == null).ToString(); //Produced "True" (without the quotes)
lbl_ValNEqNull.Text = (val != null).ToString(); //Produced "False"
lbl_ValHasVal.Text = val.HasValue.ToString(); //Produced "False"
lbl_NValHasVal.Text = (!(val.HasValue)).ToString(); //Produced "True"
lbl_ValValEqNull.Text = (val.Value == null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValValNEqNull.Text = (val.Value != null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")

Все так же, как и раньше. Имейте в виду, что инициализация с помощью int? val = new int?(null); с нулевым значением, переданным в конструктор, вызвала бы ошибку времени COMPILE, так как значение VALUE объекта, допускающего значение NULL, НЕ может иметь значение NULL. Только сам объект-оболочка может равняться нулю.

Аналогично, мы получили бы ошибку времени компиляции из:

int? val = new int?();
val.Value = null;

не говоря уже о том, что val.Value - это свойство только для чтения, а это значит, что мы даже не можем использовать что-то вроде:

val.Value = 3;

но опять же, полиморфные перегруженные операторы неявного преобразования позволят нам сделать:

val = 3;

Не нужно беспокоиться о том, что может случиться, если это работает правильно? :)

20
Perrin Larson

В VB.Net. НЕ используйте "IsNot Nothing", когда вы можете использовать ".HasValue". Я только что решил "Операция могла дестабилизировать среду выполнения" Ошибка среднего доверия, заменив "IsNot Nothing" на ".HasValue" в одном месте. Я не очень понимаю, почему, но что-то происходит по-другому в компиляторе. Я хотел бы предположить, что "! = Нуль" в C # может иметь ту же проблему.

13
Carter Medlin

Если вы используете linq и хотите, чтобы ваш код был коротким, я рекомендую всегда использовать !=null

И вот почему:

Давайте представим, что у нас есть некоторый класс Foo с переменной nullable doubleSomeDouble

public class Foo
{
    public double? SomeDouble;
    //some other properties
}   

Если где-то в нашем коде мы хотим получить все значения Foo с ненулевыми значениями SomeDouble из коллекции Foo (при условии, что некоторые значения foos в коллекции тоже могут быть нулевыми), мы получим как минимум три способа написания нашей функции (если мы используйте C # 6):

public IEnumerable<Foo> GetNonNullFoosWithSomeDoubleValues(IEnumerable<Foo> foos)
{
     return foos.Where(foo => foo?.SomeDouble != null);
     return foos.Where(foo=>foo?.SomeDouble.HasValue); // compile time error
     return foos.Where(foo=>foo?.SomeDouble.HasValue == true); 
     return foos.Where(foo=>foo != null && foo.SomeDouble.HasValue); //if we don't use C#6
}

И в такой ситуации я рекомендую всегда идти на более короткий

1
yan yankelevich