обнуляемый объект должен иметь значение

190

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

Это проблема:

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

{
  DateTime? MyDataTime;
  int? otherdata;

}

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

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

работает этот код

DateTimeExtended res = new DateTimeExtended(oldDTE);

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

Обнуляемый объект должен иметь значение.

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

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

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

Дани
источник
Какой другой конструктор?
Пол Криси
Странный. Я воспроизвожу исключение с .Value там и не получу исключения без .Value там. Вы уверены, что используете обновленный код?
Юлий
Конструктор берет экземпляр себя. как вы создаете этот первый экземпляр?
Пол Криси
он создается как new () без параметров, а затем я добавляю значения (это работает).
Дани
6
Проблема решена - проблема не была там ... был создан сгенерированный установщик для других данных и MyDateTime, который проверял значение перед его установкой .. летал, когда он нулевой !!!
Дани

Ответы:

201

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

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

В общем, плохая идея - слепо вызывать .Valueобнуляемый тип, если у вас нет предварительных знаний о том, что эта переменная ДОЛЖНА содержать значение (т. Е. Посредством .HasValueпроверки).

РЕДАКТИРОВАТЬ

Вот код для 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);

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

Yuliy
источник
Вы правы насчет .value, но что-то еще вызывает исключение. Я удалил .value и изменил порядок кода конструктора, сначала скопировав значение int, но выдается то же исключение.
Дани
Я прокомментировал вопрос - нашел проблему, это было в сгенерированном сеттере для свойств.
Дани
да, это решило мою проблему, я просто изменил нулевой способный объект на ненулевой, и преобразовал datetime в строку напрямую, а не datetimeobject.value.datetime.tostring ()
adnan
Отличный ответ. Получение исключения .Valueдля нулевого объекта имеет смысл (я полагаю), но сообщение об исключении действительно вводит в заблуждение, если вы имеете дело с двумя объектами Nullable. Что-то вроде «Свойство .Value требует, чтобы объект был ненулевым», имело бы намного больше смысла.
ДВК,
9

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

Пример:

MyEnum? type = null;
Entities.Table.Where(a => type == null || 
    a.type == (int)type).ToArray();  // Exception: Nullable object must have a value
Протектор один
источник
5
Я понимаю, что этот ответ не имеет отношения к конкретному случаю ОП, но он относится к исключению, которое он получает. Кроме того, эта страница является первым попаданием в Google для этого исключения, что делает ее актуальной.
Один защитник
6

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

DateTimeExtended(DateTimeExtended myNewDT)
{
   this.MyDateTime = myNewDT.MyDateTime;
   this.otherdata = myNewDT.otherdata;
}
Пол Криси
источник
не помогает выдает то же исключение, если я запускаю вторую строку первой.
Дани
2

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

this.MyDateTime = newDT.MyDateTime;
подветренный
источник
OldDTE не является нулевым, но я все равно удалил значение ... он все еще выбрасывает это исключение ....
Dani
1

Назначьте участников напрямую без .Valueчасти:

DateTimeExtended(DateTimeExtended myNewDT)
{
   this.MyDateTime = myNewDT.MyDateTime;
   this.otherdata = myNewDT.otherdata;
}
У Сесила есть имя
источник
0

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

Павел Радзивиловский
источник
0

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

sName = myObj.Name;

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

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

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

Juris
источник
1
Прежде чем ответить, попробуйте сначала прочитать другие ответы на вопрос - особенно принятый ответ, в котором точно указано, что вы указали в своем ответе. Хотя он не показывает это с помощью кода, он разъясняет это. Кроме того, попробуйте сделать свой пример кода соответствующим для вопроса - например this.MyDateTime = myNewDT.MyDateTime.Value;, нетsName = myObj.Name;
newfurniturey
0

Я получил это решение, и оно работает на меня

if (myNewDT.MyDateTime == null)
{
   myNewDT.MyDateTime = DateTime.Now();
}
KKG
источник