异常描述中存在悖论: 可空对象必须具有值(?!)
这是问题所在:
我有一个DateTimeExtended
班,
{
DateTime? MyDataTime;
int? otherdata;
}
和构造函数
DateTimeExtended(DateTimeExtended myNewDT)
{
this.MyDateTime = myNewDT.MyDateTime.Value;
this.otherdata = myNewDT.otherdata;
}
运行此代码
DateTimeExtended res = new DateTimeExtended(oldDTE);
使用以下消息抛出InvalidOperationException
:
Nullable对象必须有值。
myNewDT.MyDateTime.Value
- 有效且包含常规DateTime
对象。
这条消息的含义是什么?我做错了什么?
请注意,oldDTE
不是null
。我已从Value
中删除myNewDT.MyDateTime
,但由于生成的setter而引发了相同的异常。
答案 0 :(得分:166)
您应该将行this.MyDateTime = myNewDT.MyDateTime.Value;
更改为this.MyDateTime = myNewDT.MyDateTime;
您收到的异常被抛入 Nullable .Value
的 DateTime
属性中,因为它需要返回{{ 1}}(因为那是DateTime
状态的契约),但它不能这样做,因为没有.Value
返回,所以它会引发异常。
一般来说,盲目地在可空类型上调用DateTime
是个坏主意,除非您事先知道该变量必须包含一个值(即通过 .Value
检查)。
修改强>
以下是不会引发异常的.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
会导致异常。删除它摆脱了异常。我觉得你在找错了地方。
答案 1 :(得分:6)
使用LINQ扩展方法(例如Select
,Where
)时,lambda函数可能会转换为可能与C#代码行为不同的SQL。例如,C#的短路评估||
和&&
将转换为SQL的急切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
答案 2 :(得分:5)
尝试删除.value
答案 3 :(得分:2)
在这种情况下,oldDTE为null,因此当您尝试访问oldDTE.Value时,由于没有值,因此抛出InvalidOperationException。在您的示例中,您可以执行以下操作:
this.MyDateTime = newDT.MyDateTime;
答案 4 :(得分:1)
直接指定成员而不使用.Value
部分:
DateTimeExtended(DateTimeExtended myNewDT)
{
this.MyDateTime = myNewDT.MyDateTime;
this.otherdata = myNewDT.otherdata;
}
答案 5 :(得分:0)
看起来oldDTE.MyDateTime为null,所以构造函数试图把它的值 - 扔掉。
答案 6 :(得分:0)
我在尝试访问空值对象的值时收到此消息。
sName = myObj.Name;
这会产生错误。首先,你应该检查对象是否为空
if(myObj != null)
sName = myObj.Name;
这很有效。
答案 7 :(得分:0)
我有这个解决方案,它正在为我工作
if (myNewDT.MyDateTime == null)
{
myNewDT.MyDateTime = DateTime.Now();
}