Gotchas при использовании Nullable <T>в C # 4 - PullRequest
10 голосов
/ 20 июля 2010

Я только начал писать в компоненте, где я обнаружил, что было бы полезно объявить некоторые свойства обнуляемыми вместо того, чтобы позволять им прибегать к значениям по умолчанию. Однако я понял, что никогда раньше не использовал синтаксис non-nullable-type? или тип Nullable<T>, поэтому, возможно, есть некоторые ошибки, которые скоро выскочат и укусят меня. Итак ...

  • Каковы основные ошибки при использовании Nullable<T> и сокращенного синтаксиса ??

  • Как мне их обойти?

  • Каковы самые большие преимущества / новые возможности, которые открываются мне, когда я начинаю их использовать?

Ответы [ 8 ]

18 голосов
/ 20 июля 2010

Обычная ошибка пытается присвоить переменной значение 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.

Решение: Опять же, обработка нулевого случая отдельно может избежать неожиданностей.

10 голосов
/ 20 июля 2010

Люди часто удивляются тому, что не существует такого понятия, как тип значения в штучной упаковке .Если вы скажете:

int? x = 123;
int? y = null;
int z = 456;
object xx = x;
object yy = y;
object zz = z;

, вы можете подумать, что поскольку zz содержит упакованное целое число, то xx и yy содержат вставляемые в пустые целые числа.Они не.хх содержит в штучной упаковке Int.yy установлен на ноль.

1 голос
/ 20 июля 2010

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

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

actualValue = userValue ?? defaultValue;

?? является нулевым оператором объединения - вышеприведенное эквивалентно следующему:

actualValue = userValue.HasValue ? userValue : defaultValue;

или

actualValue = (userValue != null) ? userValue : defaultValue;

Искушение, которое я вижу в людях, чаще всего использует bool? как флаг с тремя состояниями. Это не имеет смысла, потому что в true / false / ??? нет третьей возможности. Тем, кто читает ваш код, придется копаться в комментариях (в лучшем случае), чтобы узнать, что true означает использование синего текста, false означает красный текст, а null означает зеленый текст. Используйте перечисления для этого.

Это самая большая ловушка, в которую я вижу, что люди попадают - кроме этого, просто привыкайте проверять, являются ли ваши nullables нулевыми - либо путем сравнения с нулем, либо с помощью .HasValue

1 голос
/ 20 июля 2010

Nullable<T> типы немного необычны;они (строго говоря) не являются ни значениями, ни ссылочными типами, а чем-то странным между ними.Бокс / распаковка и, в частности, typeof имеют специальные правила, поэтому результаты менее неожиданны.

Для подробностей я рекомендую книгу Джона Скита C # in Depth .Если вы еще не владеете им, вы должны.:)

1 голос
/ 20 июля 2010

Nullable<T> - это особый тип значения.Это может помочь, если вы понимаете, как это на самом деле работает.В этом есть несколько тонких вещей, которые не сразу очевидны.Я написал в блоге о здесь .

Фактические ошибки - не многоСамое главное, что явное приведение может выдать InvalidOperationException (а не NullReferenceException).Компилятор должен помочь вам решить любые проблемы, которые могут возникнуть.

1 голос
/ 20 июля 2010

вы можете сделать .HasValue, чтобы проверить, является ли переменная нулевой

вы можете сделать

 myvar = nullablevar ?? defaultvalue; //will set defaultvalue if nullablevar  is null

и более, это не ново для c # 4

прочитайте это для получения дополнительной информации

0 голосов
/ 20 июля 2010

Установить значение по умолчанию неосознанно при использовании nullable.Я видел это несколько раз.Например,

int? localVar = 0;
// do something ..
if (localVar.HasValue)
   _myMemberValue = localVar.Value;

Значение localVar никогда не равно нулю, поскольку оно было инициализировано значением, поэтому тест для HasValue всегда верен, и _myMemberValue может быть неправильно назначен с неправильным значением.

- Отредактировано, чтобы добавить больше комментариев ----

Забыл упомянуть.Одним из основных преимуществ, которое я видел, является использование поля для представления поля Nullable в базе данных.Это также генерируется автоматически, если вы используете Linq и EF.Но традиционно до Nullable, это ручная работа и подвержены ошибкам, чтобы обрабатывать обновление поля и решать, когда установить его со значением или на ноль.

0 голосов
/ 20 июля 2010

Я в настоящее время не использую 4.0, но в 2.0 у меня есть проблема, которая, как и большинство Generics, int?не может быть легко десериализован.Возможно, 4.0 умнее с Reflection, но стандартные утилиты XML-сериализатора не могут его прочитать.Это довольно раздражает.

...