L'oggetto nullable deve avere un valore


190

C'è un paradosso nella descrizione dell'eccezione: l'oggetto Nullable deve avere un valore (?!)

Questo è il problema:

Ho una DateTimeExtendedlezione, quello ha

{
  DateTime? MyDataTime;
  int? otherdata;

}

e un costruttore

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

in esecuzione questo codice

DateTimeExtended res = new DateTimeExtended(oldDTE);

genera un InvalidOperationExceptionmessaggio con:

L'oggetto nullable deve avere un valore.

myNewDT.MyDateTime.Value- è valido e contiene un DateTimeoggetto normale .

Qual è il significato di questo messaggio e cosa sto facendo di sbagliato?

Nota che oldDTEnon lo è null. Ho rimosso il Valueda myNewDT.MyDateTimema la stessa eccezione viene generata a causa di un setter generato.


Qual è l'altro costruttore?
Paul Creasey,

Strano. Riproduco l'eccezione con .Value e non ottengo eccezioni senza .Value. Sei sicuro di eseguire il codice aggiornato?
Yuliy,

Il costruttore prende un'istanza di se stesso. come stai creando quella prima istanza?
Paul Creasey,

è costruito come nuovo () senza parametri, quindi aggiungo i valori (funziona).
Dani,

6
Problema risolto - il problema non era presente ... c'era un setter generato per gli altri dati e MyDateTime, che stava controllando il valore prima di impostarlo ... volando quando è nullo !!!
Dani,

Risposte:


201

Dovresti cambiare la linea this.MyDateTime = myNewDT.MyDateTime.Value;in justthis.MyDateTime = myNewDT.MyDateTime;

L'eccezione che stavi ricevendo è stata lanciata nella .Valueproprietà della Nullable DateTime , in quanto è richiesta la restituzione di un DateTime(dal momento che è quello che è il contratto per gli .Valuestati), ma non può farlo perché non c'è DateTimeritorno, quindi genera un'eccezione.

In generale, è una cattiva idea invocare ciecamente .Valueun tipo nullable, a meno che non si abbia una conoscenza preliminare che quella variabile DEVE contenere un valore (cioè attraverso un .HasValuecontrollo).

MODIFICARE

Ecco il codice per DateTimeExtendedquesto non genera un'eccezione:

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

    public DateTimeExtended() { }

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

L'ho provato in questo modo:

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

L'aggiunta di .Valueon other.MyDateTimeprovoca un'eccezione. Rimuovendolo si elimina l'eccezione. Penso che tu stia guardando nel posto sbagliato.


Hai ragione sul valore .val, ma qualcos'altro causa l'eccezione. Ho rimosso il .value e ho cambiato l'ordine del codice del costrutto, copiando prima il valore int, ma viene generata la stessa eccezione.
Dani,

Ho commentato la domanda: ho riscontrato il problema, era in un setter generato per le proprietà.
Dani,

sì, il mio problema è stato risolto, cambio l'oggetto null abilitato in non abilitato nullo e converto il datetime in stringa direttamente, non tramite datetimeobject.value.datetime.tostring ()
adnan,

Bella risposta. Ottenere un'eccezione invocare .Valueun oggetto null ha senso (immagino), ma il messaggio di eccezione è davvero fuorviante se ti capita di avere a che fare con due oggetti Nullable. Qualcosa come "La proprietà .Value richiede che l'oggetto sia non nullo" avrebbe molto più senso.
DVK

9

Quando si utilizzano i metodi di estensione LINQ (ad esempio Select, Where), la funzione lambda potrebbe essere convertita in SQL che potrebbe non comportarsi in modo identico al codice C #. Ad esempio, il cortocircuito di C # è stato valutato &&e ||convertito in SQL ANDe desideroso OR. Ciò può causare problemi quando si verifica la presenza di null nel lambda.

Esempio:

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

5
Mi rendo conto che questa risposta non è pertinente al caso specifico del PO, ma è rilevante per l'eccezione che sta ricevendo. Inoltre, questa pagina è il primo successo su Google per tale eccezione, il che la rende rilevante.
Protettore uno il

6

Prova a far cadere il file .value

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

non aiuta. genera la stessa eccezione se eseguo prima la seconda riga.
Dani,

2

In questo caso oldDTE è nullo, quindi quando si tenta di accedere a oldDTE.Value viene lanciata InvalidOperationException poiché non è presente alcun valore. Nel tuo esempio puoi semplicemente fare:

this.MyDateTime = newDT.MyDateTime;

Il vecchio DTE non è nullo, ma ho rimosso comunque il valore ... sta ancora generando quell'eccezione ....
Dani,

1

Assegna i membri direttamente senza la .Valueparte:

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

0

Sembra che oldDTE.MyDateTime fosse nullo, quindi il costruttore ha cercato di prendere il suo valore - che ha lanciato.


0

Ho ricevuto questo messaggio quando provavo ad accedere ai valori di un oggetto con valore nullo.

sName = myObj.Name;

questo produrrà un errore. Innanzitutto è necessario verificare se l'oggetto non è nullo

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

Questo funziona


1
Prima di rispondere, provare a leggere le altre risposte per la domanda in primo luogo - in particolare la risposta accettata che gli stati esattamente quello che messi in vostra risposta. Sebbene non lo mostri usando il codice, lo spiega. Inoltre, prova a rendere il tuo codice di esempio pertinente alle domande - come this.MyDateTime = myNewDT.MyDateTime.Value;, nosName = myObj.Name;
newfurniturey,

0

Ho questa soluzione e funziona per me

if (myNewDT.MyDateTime == null)
{
   myNewDT.MyDateTime = DateTime.Now();
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.