异常描述中存在悖论: 可空对象必须有一个值 (?!)
这就是问题所在:
我有一个
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
,但由于生成的设置器而引发了相同的异常。
您应该将行
this.MyDateTime = myNewDT.MyDateTime.Value;
更改为 this.MyDateTime = myNewDT.MyDateTime;
您收到的异常是在 Nullable
.Value
的 DateTime
属性中抛出的,因为它需要返回 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
会导致异常。删除它可以消除异常。我认为您找错地方了。
使用 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
尝试删除
.value
DateTimeExtended(DateTimeExtended myNewDT)
{
this.MyDateTime = myNewDT.MyDateTime;
this.otherdata = myNewDT.otherdata;
}
直接分配成员,无需
.Value
部分:
DateTimeExtended(DateTimeExtended myNewDT)
{
this.MyDateTime = myNewDT.MyDateTime;
this.otherdata = myNewDT.otherdata;
}
在这种情况下,oldDTE 为 null,因此当您尝试访问 oldDTE.Value 时,会抛出 InvalidOperationException,因为没有值。在您的示例中,您可以简单地执行以下操作:
this.MyDateTime = newDT.MyDateTime;
为了回答您的实际问题,“可空对象必须有一个值”是什么意思?
我认为这是一个可怕的错误,它说“您试图获取可为空对象的 .Value,但它是 null”。
或者他们可能只是说“可为 Null 的对象必须有一个值才能获取它的 .Value”
看起来 oldDTE.MyDateTime 为空,因此构造函数尝试获取它的值 - 结果抛出了。
我在尝试访问空值对象的值时收到此消息。
sName = myObj.Name;
这会产生错误。首先你应该检查对象是否不为空
if(myObj != null)
sName = myObj.Name;
这有效。
我得到了这个解决方案,它对我有用
if (myNewDT.MyDateTime == null)
{
myNewDT.MyDateTime = DateTime.Now();
}
.价值
只能在您确定它即将到来时使用。 但由于您不确定,您只需使用“GetValueOrDefault()”。 它只会检查该值,如果没有值则设置为 Null。