首页 文章

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

提问于
浏览
13

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

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;

所以我想我的问题是为什么当我使用 ?? 时隐式类型被更改,而且在文档中我可以找到关于此的信息 .

顺便说一句,这不是一个现实世界的场景,但我想知道为什么使用 ?? 更改(隐式)类型 .

2 回答

  • 9

    一时间去找所有语言律师 . 从C#规范(版本4):

    7.13表达式的类型a ?? b取决于操作数上可用的隐式转换 . 按优先顺序排列,类型为?? b是A0,A或B,其中A是a的类型(假设a具有类型),B是b的类型(假设b具有类型),并且A0是A的基础类型,如果A是可以为空的类型,否则为A.

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

    7.14 (处理 ?: )中的语言仅从 b ? x : y 形式讨论了 xy 的实际类型,并讨论了这两种类型之间的隐式转换 .

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

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

  • 5

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

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

    反而

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

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

    表达式的类型a ?? b取决于操作数类型之间可用的隐式转换 . 按优先顺序排列,类型为?? b是A0,A或B,其中A是a的类型,B是b的类型(假设b具有类型),如果A是可空类型,则A0是A的基础类型,否则A .

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

相关问题