Nullable объект должен иметь значение

В описании исключения есть парадокс: Нулемый объект должен иметь значение (?!)

В этом проблема:

У меня есть класс DateTimeExtended который имеет

{
  DateTime? MyDataTime;
  int? otherdata;

}

и конструктор

DateTimeExtended(DateTimeExtended myNewDT)
{
   this.MyDateTime = myNewDT.MyDateTime.Value;
   this.otherdata = myNewDT.otherdata;
}

запуск этого кода

DateTimeExtended res = new DateTimeExtended(oldDTE);

выдает сообщение InvalidOperationException с сообщением:

Nullable object должен иметь значение.

myNewDT.MyDateTime.Value - действителен и содержит обычный объект DateTime.

В чем смысл этого сообщения и что я делаю неправильно?

Обратите внимание, что oldDTE не null. Я удалил Value из myNewDT.MyDateTime, но одно и то же исключение выдается из-за сгенерированного setter.

Ответ 1

Вы должны изменить строку this.MyDateTime = myNewDT.MyDateTime.Value; на this.MyDateTime = myNewDT.MyDateTime;

Исключением, которое вы получали, было выбрано свойство .Value Nullable DateTime, так как требуется вернуть DateTime (так как это что означает контракт для .Value), но он не может этого сделать, потому что нет возврата DateTime, поэтому он генерирует исключение.

В общем, это плохая идея, чтобы слепо позвонить .Value по типу с нулевым значением, если у вас нет предварительного знания о том, что эта переменная MUST содержит значение (т.е. через t28 > ).

ИЗМЕНИТЬ

Вот код для DateTimeExtended, который не генерирует исключение:

class DateTimeExtended
{
    public DateTime? MyDateTime;
    public int? otherdata;

    public DateTimeExtended() { }

    public DateTimeExtended(DateTimeExtended other)
    {
        this.MyDateTime = other.MyDateTime;
        this.otherdata = other.otherdata;
    }
}

Я протестировал его так:

DateTimeExtended dt1 = new DateTimeExtended();
DateTimeExtended dt2 = new DateTimeExtended(dt1);

Добавление .Value в other.MyDateTime вызывает исключение. Удаление из него исключает исключение. Я думаю, вы ищете не в том месте.

Ответ 2

При использовании методов расширения LINQ (например, Select, Where), лямбда-функция может быть преобразована в SQL, которая может не совпадать с вашим кодом С#. Например, оценка коротких замыканий на С# || и && преобразуется в SQL eager AND и OR. Это может вызвать проблемы при проверке нулевого значения в вашей лямбда.

Пример:

MyEnum? type = null;
Entities.Table.Where(a => type == null || 
    a.type == (int)type).ToArray();  // Exception: Nullable object must have a value

Ответ 3

Попробуйте сбросить .value

DateTimeExtended(DateTimeExtended myNewDT)
{
   this.MyDateTime = myNewDT.MyDateTime;
   this.otherdata = myNewDT.otherdata;
}

Ответ 4

В этом случае oldDTE имеет значение NULL, поэтому при попытке доступа к oldDTE.Value исключение InvalidOperationException выдается, поскольку нет значения. В вашем примере вы можете просто:

this.MyDateTime = newDT.MyDateTime;

Ответ 5

Назначьте элементы непосредственно без части .Value:

DateTimeExtended(DateTimeExtended myNewDT)
{
   this.MyDateTime = myNewDT.MyDateTime;
   this.otherdata = myNewDT.otherdata;
}

Ответ 6

Похоже, что oldDTE.MyDateTime был нулевым, поэтому конструктор попытался принять значение Value - which throw.

Ответ 7

Я получил это сообщение при попытке доступа к значениям объекта с нулевым значением.

sName = myObj.Name;

это приведет к ошибке. Сначала вы должны проверить, не объект ли null

if(myObj != null)
  sName = myObj.Name;

Это работает.