29

您可能知道,DateTime?没有参数化ToString(用于格式化输出),并且执行类似的操作

DateTime? dt = DateTime.Now;
string x;
if(dt != null)
    x = dt.ToString("dd/MM/yyyy");

会抛出

方法“ToString”没有重载需要 1 个参数

但是,由于 C# 6.0 和 Elvis ( ?.) 运算符,上面的代码可以替换为

x = dt?.ToString("dd/MM/yyyy");

哪个....有效!为什么?

4

3 回答 3

20

因为Nullable<T>在 C# 中以使该结构的实例显示为可空类型的方式实现。当你拥有DateTime?Nullable<DateTime>时,当你分配null给它时,你在幕后设置HasValuefalse当你检查时null,你正在检查HasValue,等等。?.操作符只是以一种方式实现的,它替换了相同的习语适用于引用类型也适用于可为空的结构。就像该语言的其余部分使可空结构类似于引用类型(关于null-ness)。

于 2016-01-29T10:29:57.710 回答
14

简短的回答:

DateTime?只是一种甜蜜的语法,Nullable<DateTime>它不包含DateTime' 属性和方法,而Elvis 运算符适用于 not-Nullable Nullable<DateTime>.Value


解释:

以下代码:

DateTime? dt = DateTime.Now;
string x;
if (dt != null)
    x = dt?.ToString("dd/MM/yyyy");

当反编译为C# 5.0产生以下结果:

DateTime? nullable = new DateTime?(DateTime.Now);
if (nullable.HasValue)
{
    string str = nullable.HasValue ? nullable.GetValueOrDefault().ToString("dd/MM/yyyy") : null;
}

旁注:由于在级别提升,因此在string内部声明的似乎if无关紧要MSIL,并且由于稍后在反编译器中未使用该值,因此将其显示为好像在该if范围内声明了它。

如您所见,因为DateTime?它只是 s 的一种甜美语法Nullable<DateTime>,所以使用Elvis 运算符对sC#有一个特定的引用,使其返回值是不可为空的 T 本身Nullable<T>

因此,整体的结果Elvis operator必须是Nullable,如果你想接收一个非string值,它必须是要么要么Nullable<T>aReferenceType但这并没有改变这样一个事实,即如果操作员设法自己获取Nullable<DateTime>值 - 返回DateTime的不是Nullable<DateTime>了。

于 2016-01-29T10:33:58.007 回答
2

考虑:

DateTime? dt = DateTime.Now;
string x;
if(dt != null)
    x = dt.ToString("dd/MM/yyyy");

dt是一个DateTime?Nullable<DateTime>女巫不是IFormatable而且没有ToString(string format)方法。

所以它抛出。

现在考虑:

x = dt?.ToString("dd/MM/yyyy");

The?.是一个语法糖:

dt.HasValue ? dt.Value.ToString("dd/MM/yyyy"): null

dt.Value是一个DateTime女巫IFormatable并且有一个ToString(string format)方法。

最后,在 C# 5.0 中编写第一个代码的好方法是:

DateTime? dt = DateTime.Now;
string x;
if(dt.HasValue)
    x = dt.Value.ToString("dd/MM/yyyy");
于 2016-01-29T10:44:54.990 回答