Я только что начал писать на компоненте, где я нашел, что могло бы быть полезно объявить некоторые nullable свойства, вместо того, чтобы позволить им обратиться к значениям по умолчанию. Однако я понял, что прежде никогда не использовал non-nullable-type?
синтаксис или Nullable<T>
введите прежде, таким образом, существуют, вероятно, некоторые глюки, это скоро выскочит и укусит меня. Так...
Каковы самые большие глюки при использовании Nullable<T>
и стенография ?
синтаксис?
Как я работаю вокруг них?
Каковы самые большие преимущества / новые возможности, которые сделаны доступными для меня, когда я начинаю использовать их?
Распространенная проблема - это попытка присвоения переменной, допускающей значение NULL, с помощью условного выражения, как показано ниже:
bool useDefault = true;
int defaultValue = 50;
int? y = useDefault ? defaultValue : null;
На первый взгляд может показаться, что это должно работать, но на самом деле это дает ошибку компиляции:
Type of conditional expression cannot be determined because there is no implicit conversion between 'int' and '<null>'
] Решение: добавьте приведение к одному или обоим возможным результатам:
int? y = useDefault ? defaultValue : (int?)null;
Реже встречается: обычно можно с уверенностью предположить, что для целых чисел a <= 5
и ! (A> 5 )
эквивалентны. Это предположение неверно для целых чисел, допускающих значение NULL.
int? x = null;
Console.WriteLine(x <= 5);
Console.WriteLine(!(x > 5));
Результат:
False True
Решение: обрабатывать нулевой регистр отдельно.
Вот еще один небольшой вариант вышеупомянутого:
int? y = null;
int? z = null;
Console.WriteLine(y == z);
Console.WriteLine(y <= z);
Вывод:
True False
Итак, y
равно z
, но не меньше или равно от до z
.
Решение: Опять же, отдельная обработка нулевого случая может избежать сюрпризов.
Одно из лучших применений - это то, что он достаточно хорошо отображается на поля базы данных, допускающие значение NULL - помня об этом, вы хотите использовать его так же, как пустое поле в базе данных.
То есть, нулевое значение не является «другим» - оно означает неизвестное или неисчислимое в настоящее время, или что при других значениях в этом объекте / записи, это не имеет смысла, чтобы быть значением. Ваша ситуация выглядит так, как будто она действительна - пользовательские настройки могут быть нулевыми, а фактические значения будут
actualValue = userValue ?? defaultValue;
??
- это нулевой оператор объединения - приведенное выше эквивалентно следующему:
actualValue = userValue.HasValue ? userValue : defaultValue;
или
actualValue = (userValue != null) ? userValue : defaultValue;
Я вижу, что люди чаще всего поддаются искушению, используя bool?
в качестве флага трех государств. Это не имеет смысла, потому что в true / false / ??? нет третьей возможности. Другим, читающим ваш код, придется копаться в комментариях (в лучшем случае), чтобы выяснить, что true означает использование синего текста, false означает красный текст, а null означает зеленый текст. Используйте для этого перечисления.
Это самая большая ловушка, в которую я вижу людей, - кроме этого, просто привыкните проверять, являются ли ваши значения null null - либо путем сравнения с null, либо с помощью .HasValue
Nullable
- это особый тип значения. Это может помочь, если вы поймете, как это на самом деле работает. В этом есть несколько тонких моментов, которые не сразу очевидны. Я писал о здесь .
Фактических подводных камней - немного. Пожалуй, самая большая проблема заключается в том, что явное приведение может вызвать исключение InvalidOperationException
(а не NullReferenceException
). Компилятор должен помочь вам при возникновении любых проблем.
В настоящее время я не использую 4.0, но в 2.0 у меня есть проблема, что, как и у большинства Generics, int? не может быть легко десериализован. Возможно, 4.0 умнее с Reflection, но стандартные утилиты XML-сериализатора не могут его прочитать. Это довольно неприятно.
Обнуляемые типы
немного необычны; они (строго говоря) не являются ни значениями, ни ссылочными типами, а являются чем-то странным между ними. Упаковка / распаковка и typeof
, в частности, имеют особые правила, поэтому результаты менее неожиданные.
Для получения подробной информации я рекомендую книгу Джона Скита C # in Depth . Если у вас его еще нет, вы должны это сделать. :)
вы можете сделать .HasValue, чтобы проверить, является ли переменная нулевой
вы можете сделать
myvar = nullablevar ?? defaultvalue; //will set defaultvalue if nullablevar is null
и многое другое, это не ново для c# 4
Люди часто удивляются тому, что не существует такой вещи, как упакованный тип значения, допускающий значение NULL . Если вы скажете:
int? x = 123;
int? y = null;
int z = 456;
object xx = x;
object yy = y;
object zz = z;
, вы можете подумать, что, поскольку zz содержит упакованное целое число, то xx и yy содержат упакованные целые числа, допускающие значение NULL. Они не. xx содержит заключенное в рамку int. yy имеет значение null.
Бессознательная установка значения по умолчанию при использовании nullable. Я видел это несколько раз. Например,
int? localVar = 0;
// do something ..
if (localVar.HasValue)
_myMemberValue = localVar.Value;
LocalVar никогда не бывает нулевым, потому что он был инициализирован значением, поэтому тест на HasValue всегда истинен, и _myMemberValue может быть неправильно присвоено неверное значение.
-- Отредактировано, чтобы добавить больше комментариев ----
Забыл упомянуть. Одним из основных преимуществ, которое я видел, является использование поля для представления Nullable поля в базе данных. Оно также генерируется автоматически, если вы используете Linq и EF. Но традиционно до появления Nullable, это ручная работа и склонность к ошибкам для обработки обновления поля и принятия решения о том, когда установить его со значением или в null.