小问题,只是为了理解:我有2个可空的日期时间。我读出了创建时间和更新时间,两者都可以填写。所以我想检查一下是哪个:
lastChangedIndrole = (tmpCreate > tmpUpdate ? tmpCreate : tmpUpdate);
但这里发生了一些奇怪的事情。我期望在f.e.时抛出一个错误。 tmpUpdate为null,但它似乎返回了一些东西,但不是正确的值,而只是第二个,在我的例子中是更新。
有什么我不懂的吗?我认为代码会检查到1900的毫秒数,如果有空值则会抛出错误。但这并没有发生。这是一些我不理解的魔法吗?
P.S。 :有一个特别的词吗?像vb中的IIF这样的构造函数?搜索内容很难。
感谢并在本周开了个好头
的Matthias
答案 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 > tmpUpdate
或false
为空,则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);