?使用可空类型处理的构造函数

时间:2013-08-12 11:30:56

标签: c# datetime nullable

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

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

但这里发生了一些奇怪的事情。我期望在f.e.时抛出一个错误。 tmpUpdate为null,但它似乎返回了一些东西,但不是正确的值,而只是第二个,在我的例子中是更新。

有什么我不懂的吗?我认为代码会检查到1900的毫秒数,如果有空值则会抛出错误。但这并没有发生。这是一些我不理解的魔法吗?

P.S。 :有一个特别的词吗?像vb中的IIF这样的构造函数?搜索内容很难。

感谢并在本周开了个好头

的Matthias

6 个答案:

答案 0 :(得分:3)

Nullable.Value读取时,Nullable类型为null会抛出异常。但是当它压缩它会产生意外结果时它不会抛出异常(比较null和非空值永远不会返回true)。

以下代码段将说明问题

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

此行为记录为Here

  

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

答案 1 :(得分:3)

C#将<>运算符提升为可空类型,如果其中一个参数为null,则返回false

如果tmpCreate > tmpUpdatefalse为空,则tmpCreate评估为tmpUpdate

在说明书中描述:

7.3.7解除运营商

  

•对于关系运算符&lt; &GT; &lt; =&gt; =一个提升形式的   如果操作数类型都是非可空值类型,则运算符存在   如果结果类型是bool。提升形式由   加一个?每个操作数类型的修饰符。提升的运营商   如果一个或两个操作数为null,则生成值false。除此以外,   提升的操作员解开操作数并应用底层操作   运算符产生bool结果。

答案 2 :(得分:1)

您可以比较两个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;
   }
}

答案 3 :(得分: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

结论:

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

如果您尝试读取.Value可空类型值的null属性,它将引发异常,但运算符不直接转到.Value属性,但检查首先是.HasValue属性,然后在尝试实际比较之前处理这些情况。

答案 4 :(得分: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;

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

答案 5 :(得分:1)

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

if(tmpCreate == null ^ tmpUpdate == null) lastChangedIndrole = tmpCreate ?? tmpUpdate; 其他 lastChangedIndrole =(tmpCreate&gt; tmpUpdate?tmpCreate:tmpUpdate);