3

小问题,只是为了理解:我有 2 个可以为空的日期时间。我读出了创建时间和更新时间,都可以填写。所以我想检查哪个是稍后的:

lastChangedIndrole = (tmpCreate > tmpUpdate ? tmpCreate : tmpUpdate);

但是这里发生了一些奇怪的事情。当 fe tmpUpdate 为空时,我希望抛出一个错误,但它似乎返回了一些东西,但不是正确的值,而是第二个,在我的示例中是更新。

有什么我不明白的吗?我认为代码会检查毫秒到 1900,如果有空值,则会引发错误。但这不会发生。这是我不懂的魔法吗?

PS:有没有特别的说法?像vb中的IIF这样的构造函数?很难搜索一些东西。

谢谢,本周有一个良好的开始

马蒂亚斯

4

6 回答 6

3

可空类型为空会在Nullable.Value读取时引发异常。但是它不会在比较时抛出异常,但会给出意想不到的结果(null与非空值比较永远不会返回真)。

以下片段将说明问题

DateTime? dt1 = null;
DateTime? dt2 = DateTime.Now;

bool b1 = dt2 > dt1;//false(we expect true here)
bool b2 = dt2 < dt1;//false
bool b3 = dt2 == dt1;//false

此行为记录在此处

当您对可空类型执行比较时,如果其中一个可空类型的值为 null 而另一个不是,则所有比较的结果都为 false,但 !=(不等于)除外。重要的是不要假设因为特定的比较返回 false,相反的情况返回 true。在以下示例中,10 不大于、小于或等于 null。只有 num1 != num2 的计算结果为真。

于 2013-08-12T11:41:05.737 回答
3

<C# 将and运算符提升到>可空类型之上,false如果参数之一为空,它们将返回。

因此tmpCreate > tmpUpdate评估为false如果tmpCreatetmpUpdate为空。

它在规范中描述:

7.3.7 吊运操作员

• 对于关系运算符< > <= >=,如果操作数类型都是非空值类型并且结果类型是bool,则存在运算符的提升形式。提升的形式是通过添加单个 ? 每个操作数类型的修饰符。如果一个或两个操作数为空,则提升的运算符产生值 false。否则,提升的运算符会展开操作数并应用底层运算符来生成 bool 结果。

于 2013-08-12T11:41:26.243 回答
2

您可以比较两个DateTime?对象,但大多数情况下,当至少一个操作数是null时,结果将是false

例如:

DateTime? today = DateTime.Today;
DateTime? yesterday = DateTime.Today.AddDays(-1);
DateTime? nodate = null;
DateTime? nodate2 = null;

Console.WriteLine(today > yesterday); //true
Console.WriteLine(today < yesterday); //false

Console.WriteLine(today > nodate); //false
Console.WriteLine(today == nodate); //false
Console.WriteLine(today < nodate); //false

Console.WriteLine(nodate > yesterday); //false
Console.WriteLine(nodate == yesterday); //false
Console.WriteLine(nodate < yesterday); //false

Console.WriteLine(nodate > nodate2); //false
Console.WriteLine(nodate == nodate2); //true - this is the exception
Console.WriteLine(nodate < nodate2); //false

我建议避免过于聪明,并在代码中更加明确:

if (tmpUpdate.HasValue)
{
   if (tmpCreate.HasValue)
   {
       lastChangedIndrole = (tmpCreate > tmpUpdate ? tmpCreate : tmpUpdate);
   }
   else
   {
       lastChangedIndrole = tmpUpdate;
   }
}
else
{
   if (tmpCreate.HasValue)
   {
       lastChangedIndrole = tmpCreate;
   }
   else
   {
       lastChangedIndrole = null;
   }
}
于 2013-08-12T11:41:42.697 回答
1

当您将可空值与其他可空值或不可空值进行比较时,非可空类型上的运算符被“提升”,因此也适用于它们的可空对应物。

但是,特殊处理将处理其中一个或两个都为空的情况。

这是一个LINQPad示例:

void Main()
{
    int? a = 10;
    int? b = null;

    (a > b).Dump();
    (b > a).Dump();
    (a == b).Dump();
    (a != b).Dump();
}

输出:

False
False
False
True

如您所见,当比较两个可为空的整数时,其中一个是null,只有相等运算符产生预期结果。

如果我们将a变量设为不可为空的 int:

int a = 10;

但否则保留代码,然后它会产生完全相同的结果。

如果两者都为空怎么办?

int? a = null;
int? b = null;

产生:

False
False
True
False

结论:

  • 等式运算符 ( ==and !=) 正确处理null可空类型的 s
  • 小于或大于运算符不会,false如果其中一个操作数是null,即使您切换比较,它们也会返回。基本上,10既不小于也不大于null

如果你试图读取一个可.Value为空类型值的属性null,它会抛出一个异常,但是操作符不会直接去获取该.Value属性,而是先检查该.HasValue属性,然后在尝试实际比较之前处理这些情况。

于 2013-08-12T11:43:02.547 回答
1

使用^(xor) 检查是否恰好有一个条件为真(等于 null),然后??返回第一个非 null 值。如果两者都不为空,请使用您现有的表达式。

if (tmpCreate == null ^ tmpUpdate == null)
   lastChangedIndrole = tmpCreate ?? tmpUpdate;
else
   lastChangedIndrole = (tmpCreate > tmpUpdate ? tmpCreate : tmpUpdate); 

但是您也可以选择直接分配第一个非空值,然后在 tmpUpdate 大于该值时覆盖它:

lastChangedInRole = tmpCreate ?? tmpUpdate; 
if (tmpUpdate > lastChangedInRole) 
  lastChangedInRole = tmpUpdate;

(基本原理:如果只有一个有值,则比较始终为假,非空值将使用 分配??,否则tmpCreated将分配 ,只需将其与 进行比较tmpUpdate。)

于 2013-08-12T11:50:56.910 回答
1

使用 ^ (xor) 检查是否恰好一个条件为真(等于 null)然后 ?? 返回第一个非空值。如果两者都不为空,请使用您现有的表达式。

if (tmpCreate == null ^ tmpUpdate == null) lastChangedIndrole = tmpCreate ?? tmp更新;否则 lastChangedIndrole = (tmpCreate > tmpUpdate ? tmpCreate : tmpUpdate);

于 2013-08-12T13:16:46.080 回答