可空对象必须有一个值

问题描述 投票:0回答:10

异常描述中存在悖论: 可空对象必须有一个值 (?!)

这就是问题所在:

我有一个

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
,但由于生成的设置器而引发了相同的异常。

c# nullable invalidoperationexception
10个回答
258
投票

您应该将行

this.MyDateTime = myNewDT.MyDateTime.Value;
更改为
this.MyDateTime = myNewDT.MyDateTime;

您收到的异常是在 Nullable

 
.ValueDateTime
 属性中抛出的,因为它需要返回 
DateTime
(因为这就是
.Value
的合约所规定的),但它不能这样做,因为没有
DateTime
可以返回,所以它会抛出异常。

一般来说,盲目地在可空类型上调用

.Value
是一个坏主意,除非您事先知道该变量 MUST 包含一个值(即通过
.HasValue
检查)。

编辑

这是不抛出异常的

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);

.Value
上添加
other.MyDateTime
会导致异常。删除它可以消除异常。我认为您找错地方了。


26
投票

使用 LINQ 扩展方法(例如

Select
Where
)时,lambda 函数可能会转换为 SQL,其行为可能与 C# 代码不同。例如,C# 的短路评估
&&
||
转换为 SQL 的 eager
AND
OR
。当您在 lambda 中检查 null 时,这可能会导致问题。

示例:

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

8
投票

尝试删除

.value

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

2
投票

直接分配成员,无需

.Value
部分:

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

2
投票

在这种情况下,oldDTE 为 null,因此当您尝试访问 oldDTE.Value 时,会抛出 InvalidOperationException,因为没有值。在您的示例中,您可以简单地执行以下操作:

this.MyDateTime = newDT.MyDateTime;

1
投票

为了回答您的实际问题,“可空对象必须有一个值”是什么意思?

我认为这是一个可怕的错误,它说“您试图获取可为空对象的 .Value,但它是 null”。

或者他们可能只是说“可为 Null 的对象必须有一个值才能获取它的 .Value”


0
投票

看起来 oldDTE.MyDateTime 为空,因此构造函数尝试获取它的值 - 结果抛出了。


0
投票

我在尝试访问空值对象的值时收到此消息。

sName = myObj.Name;

这会产生错误。首先你应该检查对象是否不为空

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

这有效。


0
投票

我得到了这个解决方案,它对我有用

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

0
投票

.价值

只能在您确定它即将到来时使用。 但由于您不确定,您只需使用“GetValueOrDefault()”。 它只会检查该值,如果没有值则设置为 Null。

© www.soinside.com 2019 - 2024. All rights reserved.