?。 C# 中的运算符由于未知原因未编译

?. operator in C# not compiling for unknown reason

在以下代码中,两个变体之一无法编译:

class C
{
    public decimal DecimalField;
}

static C GetC() { return new C(); } //Can return null in reality.

C c = GetC(); //Get a C value from somewhere, this might be null

string toString1 = c?.DecimalField?.ToString(); //Does not compile.
string toString2 = (c?.DecimalField)?.ToString(); //Compiles.

Error CS0023: Operator '?' cannot be applied to operand of type 'decimal'

为什么简单形式无法编译?

表达式 c?.DecimalField 不是 decimal? 类型吗?该值可以为 null,因此应该应用 ?. 运算符。我很确定是这样,因为在这段代码中:

var decimalValue = c?.DecimalField;

var 根据 IDE 解析为 decimal?

decimal类型不能为null,所以null-coalesce运算符在这里没有意义。只需将 toString1 设置为某个值即可。

如果您想在所有情况下编译它,您应该通过在您的 decimal 中添加 decimal ? insted 来编辑您要与可空类型进行比较的 DecimalField字段定义。

类型 decimal 不是可为空的类型。因此,您的第一个表达式无法编译。与第二个语句的不同之处在于,如果 cnull,则括号的内部部分可能已经是 null。因此它编译。

这可能导致 null 值:(c?.DecimalField)

结果类型为System.Nullable<decimal>或简写decimal?

您有三个变体。

您可以设置默认值,它 returns DecimalField"0":

string toString = c?.DecimalField.ToString() ?? decimal.Zero.ToString();

没有默认值,它returns DecimalFieldnull:

string toString = c?.DecimalField.ToString();

或者您可以使 DecimalField 可为空,它 returns DecimalFieldnull:

public decimal? DecimalField;
...
string toString1 = c?.DecimalField?.ToString(); //Compile now!

这是因为空条件访问运算符是 "short-circuiting"。也就是说,如果你写成a?.b.c然后执行,anull,那么不仅.b不执行,而且.c也不执行。

因此,当您编写 a?.b?.c 时,第二个空条件访问运算符不是关于检查 aa.b 是否为 null检查a.b是否为null。因此,如果 a.b 永远不可能是 null,就像您的情况一样,使用 null 条件访问运算符是没有意义的,这就是语言不允许它的原因。

这也解释了为什么 a?.b?.c(a?.b)?.c 不是一回事。

有关此的更多信息,您可以阅读 the C# Language Design Meeting notes where this was decided