在可空类型上使用coalescing null运算符更改隐式类型

时间:2012-04-16 08:07:52

标签: c# resharper implicit null-coalescing-operator

我希望接下来的三行代码是相同的:

public static void TestVarCoalescing(DateTime? nullableDateTime)
{
  var dateTimeNullable1 = nullableDateTime.HasValue ? nullableDateTime : DateTime.Now;
  var dateTimeNullable2 = nullableDateTime != null ? nullableDateTime : DateTime.Now;
  var dateTimeWhatType = nullableDateTime ?? DateTime.Now;
}

在所有情况下,我都会将nullableDateTime分配给新变量。我希望所有变量的类型都变为DateTime?,因为这是nullableDateTime的类型。但令我惊讶的是,dateTimeWhatType的类型只变为DateTime,因此不可为空。

更糟糕的是,ReSharper建议用空合并表达式替换第二个语句,将其转换为表达式3.因此,如果我让ReSharper执行它的操作,变量的类型将从DateTime?更改为DateTime

事实上,让我们说在方法的其余部分,我会使用

if (someCondition) dateTimeNullable2 = null;

那会编译得很好,直到我让ReSharper用空合并版本替换第二个表达式。

AFAIK,取代

somevar != null ? somevar : somedefault;

somevar ?? somedefault;

确实应该产生相同的结果。但是对于可空类型的隐式类型,编译器似乎威胁??就像它意味着一样。

somevar != null ? somevar.Value : somedefault;

所以我想我的问题是当我使用??时隐式类型被更改的原因,以及文档中我可以找到关于此的信息。

BTW,这不是真实世界的情况,但我想知道为什么使用??更改(隐式)类型。

2 个答案:

答案 0 :(得分:9)

你的前两个例子让你误入歧途;更好的是不要考虑你的

var dateTimeNullable1 = nullableDateTime.HasValue 
    ? nullableDateTime 
    : DateTime.Now;

而是

var dateTimeNullable1 = nullableDateTime.HasValue 
    ? nullableDateTime.Value 
    : DateTime.Now;

引用C#3.0规范的第7.12节“空合并运算符”(略微粗略格式化的道歉):

  

表达式a ?? b的类型取决于哪个隐式   操作数类型之间可以进行转换。为了   首选项,a ?? b的类型为A 0 AB,   其中Aa的类型,Bb的类型(前提是   b有一个类型),A 0 A的基础类型   A是可以为空的类型,否则为A

因此,如果aNullable<Something>,并且b可以隐式转换为Something,则整个表达式的类型将为Something。正如@Damien_The_Unbeliever建议的那样,此运算符的 point 是合并空值!

答案 1 :(得分:5)

暂时去找所有语言律师。来自C#规范(版本4):

  

<强> 7.13

     

表达式a ?? b的类型取决于操作数上可用的隐式转换。按优先顺序排列,a ?? b的类型为A0AB,其中Aa的类型(已提供) a具有类型),Bb的类型(假设b具有类型),A0A的基础类型如果A是可以为空的类型,则为{1}},否则为A

因此,如果第一个表达式是可空类型,??被明确定义为首选表达式的基础类型。

来自 7.14 (处理?:)的语言仅从x形式讨论yb ? x : y的实际类型,并讨论这两种类型之间的隐式转换。

  

如果从X到Y存在隐式转换(第6.1节),而不是从Y到X,则Y是条件表达式的类型

由于Nullable(T)定义了从TNullable(T)隐式转换,并且Nullable(T)只转换了显式转换} T,整个表达式唯一可能的类型是Nullable(T)