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;
Это работает.