L'objet nullable doit avoir une valeur

190

Il y a un paradoxe dans la description de l'exception: l'objet Nullable doit avoir une valeur (?!)

C'est le problème:

J'ai une DateTimeExtendedclasse, qui a

{
  DateTime? MyDataTime;
  int? otherdata;

}

et un constructeur

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

exécuter ce code

DateTimeExtended res = new DateTimeExtended(oldDTE);

jette un InvalidOperationExceptionavec le message:

L'objet Nullable doit avoir une valeur.

myNewDT.MyDateTime.Value- est valide et contient un DateTimeobjet normal .

Quelle est la signification de ce message et qu'est-ce que je fais de mal?

Notez que oldDTEnon null. J'ai supprimé Valuede myNewDT.MyDateTimemais la même exception est levée en raison d'un setter généré.

Dani
la source
Quel est l'autre constructeur?
Paul Creasey
Étrange. Je reproduis l'exception avec le .Value là-bas, et n'obtiens aucune exception sans le .Value là-bas. Êtes-vous sûr d'exécuter le code mis à jour?
Yuliy
Le constructeur prend une instance de lui-même. comment créez-vous cette première instance?
Paul Creasey
il est construit comme new () sans paramètres, puis j'ajoute les valeurs (cela fonctionne).
Dani
6
Problème résolu - le problème n'était pas là ... il y avait un setter généré pour les autres données et MyDateTime, qui vérifiait la valeur avant de le définir .. volant quand c'est nul !!!
Dani

Réponses:

201

Vous devriez changer la ligne this.MyDateTime = myNewDT.MyDateTime.Value;en justethis.MyDateTime = myNewDT.MyDateTime;

L'exception que vous receviez a été lancée dans la .Valuepropriété du Nullable DateTime , car il est nécessaire de retourner un DateTime(puisque c'est ce que le contrat pour les .Valueétats), mais il ne peut pas le faire car il n'y a pas DateTimede retour, donc il lève une exception.

En général, c'est une mauvaise idée d'appeler aveuglément .Valueun type Nullable, sauf si vous avez une certaine connaissance préalable que cette variable DOIT contenir une valeur (c'est-à-dire via une .HasValuevérification).

ÉDITER

Voici le code pour DateTimeExtendedcela ne lève pas d'exception:

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

    public DateTimeExtended() { }

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

Je l'ai testé comme ceci:

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

L'ajout de .Valueon other.MyDateTimeprovoque une exception. Le supprimer supprime l'exception. Je pense que vous cherchez au mauvais endroit.

Yuliy
la source
Vous avez raison sur le .value, mais quelque chose d'autre provoque l'exception. J'ai supprimé le .value, et j'ai changé l'ordre du code du constructeur en copiant d'abord la valeur int, mais la même exception est levée.
Dani
J'ai commenté la question - j'ai trouvé le problème, c'était dans un setter généré pour les propriétés.
Dani
oui, cela a résolu mon problème, je change juste l'objet null capable en non null capable, et convertis datetime en chaîne directement, pas par datetimeobject.value.datetime.tostring ()
adnan
Très bonne réponse. Obtenir une exception appelant .Valueun objet nul a du sens (je suppose), mais le message d'exception est vraiment trompeur si vous avez affaire à deux objets Nullable. Quelque chose comme «La propriété .Value exige que l'objet soit non nul» aurait beaucoup plus de sens.
DVK
9

Lors de l'utilisation de méthodes d'extension LINQ (par exemple Select, Where), la fonction lambda peut être convertie en SQL qui peut ne pas se comporter de manière identique à votre code C #. Par exemple, le court-circuit de C # évalué &&et ||converti en SQL hâte ANDet OR. Cela peut poser des problèmes lorsque vous vérifiez la valeur null dans votre lambda.

Exemple:

MyEnum? type = null;
Entities.Table.Where(a => type == null || 
    a.type == (int)type).ToArray();  // Exception: Nullable object must have a value
Protecteur un
la source
5
Je me rends compte que cette réponse n'est pas pertinente pour le cas spécifique du PO, mais elle est pertinente pour l'exception qu'il reçoit. En outre, cette page est le premier appel sur Google pour cette exception, ce qui la rend pertinente.
Protector one
6

Essayez de laisser tomber le .value

DateTimeExtended(DateTimeExtended myNewDT)
{
   this.MyDateTime = myNewDT.MyDateTime;
   this.otherdata = myNewDT.otherdata;
}
Paul Creasey
la source
n'aide pas. il jette la même exception si je lance la deuxième ligne en premier.
Dani
2

Dans ce cas, oldDTE est nul, donc lorsque vous essayez d'accéder à oldDTE.Value, l'exception InvalidOperationException est levée car il n'y a aucune valeur. Dans votre exemple, vous pouvez simplement faire:

this.MyDateTime = newDT.MyDateTime;
Lee
la source
L'oldDTE n'est pas nul, mais j'ai quand même supprimé la valeur ... il lève toujours cette exception ....
Dani
1

Affectez les membres directement sans la .Valuepièce:

DateTimeExtended(DateTimeExtended myNewDT)
{
   this.MyDateTime = myNewDT.MyDateTime;
   this.otherdata = myNewDT.otherdata;
}
Cecil a un nom
la source
0

On dirait que oldDTE.MyDateTime était nul, donc le constructeur a essayé de prendre sa valeur - ce qui a jeté.

Pavel Radzivilovsky
la source
0

J'ai reçu ce message en essayant d'accéder aux valeurs d'un objet à valeur nulle.

sName = myObj.Name;

cela produira une erreur. Vous devez d'abord vérifier si l'objet n'est pas nul

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

Cela marche.

Juris
la source
1
Avant de répondre, essayez d'abord de lire les autres réponses à la question - en particulier la réponse acceptée qui indique exactement ce que vous avez placé dans votre réponse. Bien qu'il ne le montre pas à l'aide de code, il le précise. Essayez également de rendre votre exemple de code pertinent par rapport à la question - par exemple this.MyDateTime = myNewDT.MyDateTime.Value;, nonsName = myObj.Name;
newfurniturey
0

J'ai cette solution et ça marche pour moi

if (myNewDT.MyDateTime == null)
{
   myNewDT.MyDateTime = DateTime.Now();
}
KKG
la source