об'ємний об'єкт повинен мати значення


190

У описі винятків є парадокс: об'єкт Nullable повинен мати значення (?!)

Це проблема:

У мене є 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 там. Ви впевнені, що використовуєте оновлений код?
Юлій

Конструктор бере екземпляр себе. як ти створюєш цю першу інстанцію?
Пол Крісі

він будується як новий () без параметрів, а потім додаю значення (це працює).
Дані

6
Проблема вирішена - проблеми не було ... був створений сетер для іншихданих та MyDateTime, який перевіряв значення перед тим, як його встановити.
Дані

Відповіді:


201

Ви повинні змінити лінію this.MyDateTime = myNewDT.MyDateTime.Value;на справедливуthis.MyDateTime = myNewDT.MyDateTime;

Виняток, який ви отримали, був кинутий у .Valueвласність Nullable DateTime , оскільки потрібно повернути DateTime(оскільки це договір для .Valueштатів), але він не може цього зробити, тому що DateTimeповернення немає , тому він викидає виняток.

Загалом, це погана ідея сліпо викликати .Valueнульовий тип, якщо ви не маєте попередніх знань, що ця змінна ОБОВ'ЯЗКОВО містить значення (тобто через .HasValueчек).

EDIT

Ось код для 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викликає виняток. Видалення його позбавляється від винятку. Я думаю, ти шукаєш не в тому місці.


Ви маєте рацію щодо .value, але щось інше спричиняє виняток. Я вилучив значення.
Дані

Я прокоментував це питання - знайшов проблему, вона була в створеному сетері для властивостей.
Дані

так, це вирішило мою проблему, я просто змінив об’єкт, що містить null, на недійсний, і перетворити дату в строку безпосередньо, а не по datetimeobject.value.datetime.tostring ()
adnan

Чудова відповідь. Отримати виняток із закликом .Valueдо об’єкта з нулем має сенс (я думаю), але повідомлення про виключення є дійсно оманливим, якщо трапляється мати справу з двома об'єктами Nullable. Щось на кшталт "Властивості .Value вимагає, щоб об'єкт був ненульовим", мав би набагато більше сенсу.
DVK

9

При використанні методів розширення LINQ (наприклад Select, Where) функція лямбда може бути перетворена в SQL, яка може не поводитися однаково з вашим кодом C #. Наприклад, оцінюється коротке замикання 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-й рядок першим.
Дані

2

У цьому випадку oldDTE є нульовим, тому при спробі отримати доступ до oldDTE.Value InvalidOperationException кидається, оскільки значення не має. У вашому прикладі ви можете просто зробити:

this.MyDateTime = newDT.MyDateTime;

OldDTE не є нульовим, але я все одно вилучив значення ... воно все одно кидає це виняток ....
Dani

1

Призначте членів безпосередньо без .Valueчастини:

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


0

Я отримав це повідомлення під час спроби отримати доступ до значень об'єкта з нульовим значенням.

sName = myObj.Name;

це призведе до помилок. Спочатку слід перевірити, чи об’єкт не є нульовим

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

Це працює.


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

0

Я отримав це рішення, і воно працює на мене

if (myNewDT.MyDateTime == null)
{
   myNewDT.MyDateTime = DateTime.Now();
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.