zerowalny obiekt musi mieć wartość

190

W opisie wyjątku występuje paradoks: Obiekt dopuszczający wartości zerowe musi mieć wartość (?!)

To jest problem:

Mam DateTimeExtendedklasę

{
  DateTime? MyDataTime;
  int? otherdata;

}

i konstruktor

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

uruchomienie tego kodu

DateTimeExtended res = new DateTimeExtended(oldDTE);

rzuca InvalidOperationExceptionz komunikatem:

Obiekt zerowalny musi mieć wartość.

myNewDT.MyDateTime.Value- jest ważny i zawiera zwykły DateTimeobiekt.

Jakie jest znaczenie tego przesłania i co robię źle?

Zauważ, że oldDTEnie jest null. Usunąłem Valuez, myNewDT.MyDateTimeale ten sam wyjątek został zgłoszony z powodu wygenerowanego setera.

Dani
źródło
Jaki jest drugi konstruktor?
Paul Creasey,
Dziwne. Odtwarzam wyjątek z .Value tam i nie otrzymuję wyjątku bez .Value tam. Czy na pewno używasz zaktualizowanego kodu?
Yuliy,
Konstruktor przyjmuje instancję samego siebie. jak tworzysz tę pierwszą instancję?
Paul Creasey,
jest skonstruowany jako new () bez parametrów, a następnie dodaję wartości (działa).
Dani,
6
Problem rozwiązany - problemu nie było ... wygenerowano seter dla otherdata i MyDateTime, który sprawdzał wartość przed jej ustawieniem .. latający, gdy jest zerowy !!!
Dani,

Odpowiedzi:

201

Powinieneś zmienić linię this.MyDateTime = myNewDT.MyDateTime.Value;na justthis.MyDateTime = myNewDT.MyDateTime;

Wyjątek, który otrzymałeś, został zgłoszony we .Valuewłaściwości Nullable DateTime , ponieważ jest on wymagany do zwrócenia DateTime(ponieważ taka jest umowa dla .Valuestanów), ale nie może tego zrobić, ponieważ nie ma DateTimezwrotu, więc zgłasza wyjątek.

Ogólnie rzecz biorąc, złym pomysłem jest ślepe wywoływanie .Valuetypu zerowalnego, chyba że masz wcześniejszą wiedzę, że ta zmienna MUSI zawierać wartość (np. Poprzez .HasValuesprawdzenie).

EDYTOWAĆ

Oto kod DateTimeExtended, który nie zgłasza wyjątku:

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

    public DateTimeExtended() { }

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

Testowałem to w ten sposób:

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

Dodanie .ValueON other.MyDateTimespowoduje wyjątek. Usunięcie go pozbywa się wyjątku. Myślę, że szukasz w złym miejscu.

Julia
źródło
Masz rację co do .value, ale coś innego powoduje wyjątek. Usunąłem .value i zmieniłem kolejność kodu konstruktora - najpierw kopiując wartość int, ale zgłaszany jest ten sam wyjątek.
Dani,
Skomentowałem pytanie - znalazłem problem, to było w generatorze ustawień właściwości.
Dani,
tak, rozwiązał mój problem, po prostu zmieniam obiekt null zdolny na inny niż null zdolny i przekształcam datetime bezpośrednio na ciąg znaków, a nie przez datetimeobject.value.datetime.tostring ()
adnan
Świetna odpowiedź. Wydaje się, że uzyskanie wyjątku wywołującego .Valueobiekt zerowy ma sens (tak mi się wydaje), ale komunikat wyjątku jest bardzo mylący, jeśli masz do czynienia z dwoma obiektami zerowalnymi. Coś w rodzaju „Właściwość .Value wymaga, aby obiekt nie był zerowy”, miałoby o wiele więcej sensu.
DVK
9

Przy użyciu metody rozszerzenie LINQ (np Select, Where), funkcja lambda może być konwertowane do SQL, które nie mogą zachowywać się identycznie do kodu C #. Na przykład, zwarcie C # jest oceniane &&i ||są konwertowane na chętny ANDi SQL OR. Może to powodować problemy podczas sprawdzania wartości zerowej w lambda.

Przykład:

MyEnum? type = null;
Entities.Table.Where(a => type == null || 
    a.type == (int)type).ToArray();  // Exception: Nullable object must have a value
Protektor jeden
źródło
5
Zdaję sobie sprawę, że ta odpowiedź nie dotyczy konkretnego przypadku PO, ale dotyczy wyjątku, który się pojawia. Ponadto ta strona jest pierwszym działaniem Google dla tego wyjątku, co czyni go istotnym.
Protektor jeden
6

Spróbuj upuścić .value

DateTimeExtended(DateTimeExtended myNewDT)
{
   this.MyDateTime = myNewDT.MyDateTime;
   this.otherdata = myNewDT.otherdata;
}
Paul Creasey
źródło
nie pomaga rzuca ten sam wyjątek, jeśli najpierw uruchomię 2. linię.
Dani,
2

W tym przypadku oldDTE ma wartość NULL, więc przy próbie uzyskania dostępu do oldDTE.Value zgłaszany jest wyjątek InvalidOperationException, ponieważ nie ma żadnej wartości. W twoim przykładzie możesz po prostu zrobić:

this.MyDateTime = newDT.MyDateTime;
Zawietrzny
źródło
OldDTE nie ma wartości zerowej, ale mimo to usunąłem wartość ... nadal rzuca ten wyjątek ....
Dani,
1

Przypisuj członków bezpośrednio bez .Valueczęści:

DateTimeExtended(DateTimeExtended myNewDT)
{
   this.MyDateTime = myNewDT.MyDateTime;
   this.otherdata = myNewDT.otherdata;
}
Cecil ma nazwę
źródło
0

Wygląda na to, że oldDTE.MyDateTime ma wartość NULL, więc konstruktor próbował przyjąć jego wartość - która wyrzuciła.

Pavel Radzivilovsky
źródło
0

Otrzymałem ten komunikat podczas próby uzyskania dostępu do wartości obiektu o wartości zerowej.

sName = myObj.Name;

spowoduje to błąd. Najpierw sprawdź, czy obiekt nie jest pusty

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

To działa.

Juris
źródło
1
Przed udzieleniem odpowiedzi, spróbuj przeczytać innych odpowiedzi na pytanie pierwsze - zwłaszcza przyjętym odpowiedź, że stany dokładnie co umieściłeś w swojej odpowiedzi. Chociaż nie pokazuje go za pomocą kodu, to przeliteruje. Staraj się również, aby twój przykładowy kod był odpowiedni dla pytania - na przykład this.MyDateTime = myNewDT.MyDateTime.Value;niesName = myObj.Name;
newfurniturey
0

Mam to rozwiązanie i działa dla mnie

if (myNewDT.MyDateTime == null)
{
   myNewDT.MyDateTime = DateTime.Now();
}
KKG
źródło