Objeto nullable debe tener un valor

190

Hay una paradoja en la descripción de la excepción: el objeto anulable debe tener un valor (?!)

Este es el problema:

Tengo una DateTimeExtendedclase que tiene

{
  DateTime? MyDataTime;
  int? otherdata;

}

y un constructor

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

ejecutando este código

DateTimeExtended res = new DateTimeExtended(oldDTE);

arroja un InvalidOperationExceptioncon el mensaje:

Objeto nullable debe tener un valor.

myNewDT.MyDateTime.Value- es válido y contiene un DateTimeobjeto regular .

¿Cuál es el significado de este mensaje y qué estoy haciendo mal?

Tenga en cuenta que oldDTEno lo es null. He quitado el Valuede myNewDT.MyDateTimepero la misma excepción se produce debido a un colocador generado.

Dani
fuente
¿Cuál es el otro constructor?
Paul Creasey
Extraño. Reproduzco la excepción con el .Value allí, y no obtengo ninguna excepción sin el .Value allí. ¿Estás seguro de que estás ejecutando el código actualizado?
Yuliy
El constructor toma una instancia de sí mismo. ¿Cómo estás creando esa primera instancia?
Paul Creasey
se construye como new () sin parámetros, y luego agrego los valores (funciona).
Dani el
66
Problema resuelto: el problema no estaba allí ... había un setter generado para los otros datos y MyDateTime, que estaba verificando el valor antes de configurarlo ... ¡¡¡volando cuando es nulo !!!
Dani el

Respuestas:

201

Deberías cambiar la línea this.MyDateTime = myNewDT.MyDateTime.Value;a solothis.MyDateTime = myNewDT.MyDateTime;

La excepción que estaba recibiendo fue lanzada en la .Valuepropiedad de Nullable DateTime , ya que se requiere que devuelva un DateTime(ya que ese es el contrato para los .Valueestados), pero no puede hacerlo porque no hay DateTimedevolución, por lo que arroja una excepción.

En general, es una mala idea llamar ciegamente .Valuea un tipo anulable, a menos que tenga algún conocimiento previo de que esa variable DEBE contener un valor (es decir, a través de una .HasValueverificación).

EDITAR

Aquí está el código para DateTimeExtendedeso no arroja una excepción:

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

    public DateTimeExtended() { }

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

Lo probé así:

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

Agregar el .Valueencendido other.MyDateTimeprovoca una excepción. Eliminarlo elimina la excepción. Creo que estás buscando en el lugar equivocado.

Yuliy
fuente
Tienes razón sobre el valor. Sin embargo, algo más causa la excepción. He eliminado el .value, y he cambiado el orden del código del constructor, copiando el valor int primero, pero se produce la misma excepción.
Dani el
He comentado la pregunta: encontré el problema, estaba en un setter generado para las propiedades.
Dani
sí, resolvió mi problema, simplemente cambio el objeto nulo capaz a no nulo capaz, y convierto datetime en cadena directamente, no por datetimeobject.value.datetime.tostring ()
adnan
Gran respuesta. Obtener una excepción llamando .Valuea un objeto nulo tiene sentido (supongo), pero el mensaje de excepción es realmente engañoso si se trata de dos objetos Nullable. Algo como 'La propiedad .Value requiere que el objeto sea no nulo' tendría mucho más sentido.
DVK
9

Cuando se utilizan métodos de extensión LINQ (por ejemplo Select, Where), la función lambda puede convertirse a SQL que puede no comportarse de manera idéntica a su código C #. Por ejemplo, el cortocircuito de C # se evalúa &&y ||se convierte en el ansioso ANDy de SQL OR. Esto puede causar problemas cuando está buscando nulos en su lambda.

Ejemplo:

MyEnum? type = null;
Entities.Table.Where(a => type == null || 
    a.type == (int)type).ToArray();  // Exception: Nullable object must have a value
Protector uno
fuente
55
Me doy cuenta de que esta respuesta no es relevante para el caso específico del OP, pero es relevante para la excepción que está recibiendo. Además, esta página es el primer éxito en Google para esa excepción, lo que la hace relevante.
Protector uno
6

Intenta soltar el .value

DateTimeExtended(DateTimeExtended myNewDT)
{
   this.MyDateTime = myNewDT.MyDateTime;
   this.otherdata = myNewDT.otherdata;
}
Paul Creasey
fuente
no ayuda arroja la misma excepción si corro la segunda línea primero.
Dani
2

En este caso, oldDTE es nulo, por lo tanto, cuando intente acceder a oldDTE.Value, se arroja InvalidOperationException ya que no hay ningún valor. En su ejemplo, simplemente puede hacer:

this.MyDateTime = newDT.MyDateTime;
Sotavento
fuente
El oldDTE no es nulo, pero de todos modos eliminé el valor ... todavía está lanzando esa excepción ...
Dani
1

Asigne los miembros directamente sin la .Valueparte:

DateTimeExtended(DateTimeExtended myNewDT)
{
   this.MyDateTime = myNewDT.MyDateTime;
   this.otherdata = myNewDT.otherdata;
}
Cecil tiene un nombre
fuente
0

Parece que oldDTE.MyDateTime era nulo, por lo que el constructor intentó tomar su valor, lo que arrojó.

Pavel Radzivilovsky
fuente
0

Recibí este mensaje al intentar acceder a los valores de un objeto con valor nulo.

sName = myObj.Name;

Esto producirá un error. Primero debe verificar si el objeto no es nulo

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

Esto funciona.

Juris
fuente
1
Antes de responder, intente leer primero las otras respuestas para la pregunta, especialmente la respuesta aceptada que indica exactamente lo que colocó en su respuesta. Aunque no lo muestra usando código, lo explica. Además, trate de hacer que el código ejemplo relevante a la pregunta de - como por ejemplo this.MyDateTime = myNewDT.MyDateTime.Value;, nosName = myObj.Name;
newfurniturey
0

Tengo esta solución y está funcionando para mí.

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