Я всегда использовал, Nullable<>.HasValue
потому что мне понравилась семантика. Тем не менее, недавно я работал над чьей-либо существующей кодовой базой, где они использовали Nullable<> != null
исключительно вместо этого.
Есть ли причина использовать один над другим или это просто предпочтение?
int? a; if (a.HasValue) // ...
против
int? b; if (b != null) // ...
HasValue
так как я думаю, что слова, как правило, более читабельны, чем символы. Это все зависит от вас, и то, что соответствует вашему существующему стилю..HasValue
имеет больше смысла, так как обозначает, что тип имеет тип,T?
а не тип, который может быть обнуляемым, например строки.Ответы:
Компилятор заменяет пустые сравнения на вызовы
HasValue
, поэтому разницы нет. Просто делайте то, что лучше для чтения / имеет больше смысла для вас и ваших коллег.источник
int? x = null
дает мне иллюзию, что обнуляемый экземпляр является ссылочным типом. Но правда в том, что Nullable <T> является типом значения. Он чувствует , что я получаю NullReferenceException сделать:int? x = null; Use(x.HasValue)
.Nullable<int>
вместоint?
.Я предпочитаю,
(a != null)
чтобы синтаксис соответствовал ссылочным типам.источник
Nullable<>
это не ссылочный тип.HasValue
потому что это более читабельно, чем!= null
Я провел некоторое исследование по этому вопросу, используя различные методы для присвоения значений обнуляемому int. Вот что случилось, когда я делал разные вещи. Следует уточнить, что происходит. Имейте в виду:
Nullable<something>
или сокращениеsomething?
- это структура, для которой компилятор, кажется, проделывает большую работу, чтобы позволить нам использовать с нулем, как если бы это был класс.Как вы увидите ниже,
SomeNullable == null
иSomeNullable.HasValue
всегда будет возвращать ожидаемый истинным или ложным. Хотя это и не показано ниже,SomeNullable == 3
это также верно (если предположить, что SomeNullable являетсяint?
).В то время как
SomeNullable.Value
получает нам сообщение об ошибке выполнения , если мы назначилиnull
наSomeNullable
. Фактически это единственный случай, когда обнуляемые значения могут вызвать у нас проблему, благодаря комбинации перегруженных операторов, перегруженныхobject.Equals(obj)
метод и оптимизация компилятора и бизнес обезьян.Вот описание некоторого кода, который я запустил, и какой вывод он произвел в метках:
Хорошо, давайте попробуем следующий метод инициализации:
Все так же, как и раньше. Имейте в виду, что инициализация с
int? val = new int?(null);
нулем, переданным в конструктор, привела бы к ошибке времени COMPILE, так как значение VALUE объекта, допускающего значение NULL, НЕ может иметь значение NULL. Только сам объект-оболочка может равняться нулю.Аналогично, мы получили бы ошибку времени компиляции из:
не говоря уже о том, что
val.Value
это свойство только для чтения, то есть мы не можем даже использовать что-то вроде:но опять же, полиморфные перегруженные операторы неявного преобразования позволят нам сделать:
Не нужно беспокоиться о том, что может случиться, если это работает правильно? :)
источник
Nullable<X>
наберете VisualStudio 2013 и F12, вы увидите, что он перегружает только преобразованиеX
вEquals(object other)
метод и из него и метод. Тем не менее, я думаю, что оператор == использует этот метод по умолчанию, поэтому эффект тот же. Я действительно хотел обновить этот ответ некоторое время, но я ленив и / или занят. Этот комментарий придется сделать сейчас :)int? val = 42; val.GetType() == typeof(int)
). Так что не только nullable структура, которая может быть равна нулю, это также часто вообще не nullable! : D Точно так же, когда вы упаковываете значение, допускающее значение NULL, вы упаковываетеint
, а неint?
- и когдаint?
оно не имеет значения, вы получаетеnull
вместо значения в штучной упаковке значение NULL. По сути, это означает, что при правильном использованииNull
тип в .NET? Можете ли вы указать на часть в спецификации CLR / C #, где это сказано? Nullables хорошо определены в спецификации CLR, их поведение не является «реализацией абстракции» - это контракт . Но если лучшее, что вы можете сделать - это нападения ad hominem, наслаждайтесь.В VB.Net. НЕ используйте «IsNot Nothing», когда вы можете использовать «.HasValue». Я только что решил «Операция могла дестабилизировать среду выполнения» Ошибка среднего доверия, заменив «IsNot Nothing» на «.HasValue» в одном месте. Я не очень понимаю, почему, но что-то происходит по-другому в компиляторе. Я хотел бы предположить, что "! = Нуль" в C # может иметь ту же проблему.
источник
HasValue
из-за читабельности.IsNot Nothing
действительно уродливое выражение (из-за двойного отрицания).Если вы используете linq и хотите, чтобы ваш код был коротким, я рекомендую всегда использовать
!=null
И вот почему:
Давайте представим, что у нас есть некоторый класс
Foo
с двойной переменнойSomeDouble
Если где-то в нашем коде мы хотим получить все значения Foo с ненулевыми значениями SomeDouble из коллекции Foo (при условии, что некоторые значения foos в коллекции тоже могут быть нулевыми), мы получим как минимум три способа написания нашей функции (если мы используйте C # 6):
И в такой ситуации я рекомендую всегда идти на более короткий
источник
foo?.SomeDouble.HasValue
это ошибка времени компиляции (не «бросок» в моей терминологии) в этом контексте, потому что ее тип -bool?
не простоbool
. (.Where
Метод хочет aFunc<Foo, bool>
.) Разрешается делать(foo?.SomeDouble).HasValue
, конечно, так как это имеет типbool
. Это то, что ваша первая строка «переводит» во внутреннюю сторону компилятором C # (по крайней мере, формально).Общий ответ и практическое правило: если у вас есть возможность (например, написание пользовательских сериализаторов) обрабатывать Nullable в другом конвейере, чем
object
- и использовать их специфические свойства - делайте это и используйте специфические свойства Nullable. Так что с точки зрения последовательного мышленияHasValue
следует отдавать предпочтение. Последовательное мышление может помочь вам написать лучший код, не тратя слишком много времени на детали. Например, второй метод будет во много раз эффективнее (в основном из-за встраивания компиляторов и бокса, но все же числа очень выразительны):Контрольный тест:
Код теста:
https://github.com/dotnet/BenchmarkDotNet был использован
PS . Люди говорят, что совет «предпочитаю HasValue из-за последовательного мышления» не связан и бесполезен. Можете ли вы предсказать производительность этого?
Люди PPS продолжают минус, но никто не пытается предсказать производительность
CheckNullableGenericImpl
. И там компилятор не поможет вам заменить!=null
наHasValue
.HasValue
следует использовать напрямую, если вы заинтересованы в производительности.источник
CheckObjectImpl
ящики обнуляютсяobject
, тогдаCheckNullableImpl
как не использует бокс. Таким образом, сравнение очень несправедливо. Мало того, что это не плата за проезд, это также бесполезно, потому что, как отмечено в принятом ответе , компилятор переписывает!=
вHasValue
любом случае.Nullable<T>
, которую вы делаете (упаковывая ее вobject
). Когда вы применяете!= null
со значением nullable слева, бокс не возникает, потому что поддержка!=
для nullables работает на уровне компилятора. Другое дело, когда вы скрываете nullable от компилятора, сначала поместив его вobject
. НиCheckObjectImpl(object o)
ваш эталонный тест не имеет смысла в принципе.CheckObjectImpl
его тело внутриCheckObject
. Однако ваши последние комментарии показывают, что на самом деле вы имели в виду совершенно другой вопрос, когда решили ответить на этот восьмилетний вопрос, что вводит ваш ответ в заблуждение в контексте исходного вопроса. Это было не то, о чем спрашивал ОП.what is faster != or HasValue
. Он приходит к этому вопросу, просматривает ваш ответ, оценивает ваш тест и говорит: «Ну и дела, я никогда не буду использовать,!=
потому что он явно намного медленнее!» Это очень неправильный вывод, который он затем распространит. Вот почему я считаю, что ваш ответ вреден - он отвечает на неправильный вопрос и, таким образом, привносит неверное заключение в ничего не подозревающего читателя. Рассмотрим , что происходит , когда вы меняете ,CheckNullableImpl
чтобы также бытьreturn o != null;
вы получите тот же результат теста.!=
иHasValue
когда фактически он показывает разницу междуobject o
иT? o
. Если вы сделаете то, что я предложил, то есть переписатьCheckNullableImpl
какpublic static bool CheckNullableImpl<T>(T? o) where T: struct { return o != null; }
, вы получите эталонный тест, который ясно показывает, что!=
намного медленнее, чем!=
. Что должно привести вас к выводу, что проблема, о которой говорится в вашем ответе, вовсе не касается!=
противHasValue
.