1

例如,给定以下代码:

int? ReallyComplexFunction()
{
    return 2; // Imagine this did something that took a while
}

void Something()
{
    int i = ReallyCleverFunction() ?? 42;
}

...是否保证该函数只会被调用一次?在我的测试中,它只被调用一次,但我看不到任何文件说明我可以依赖它总是如此。

编辑

我可以猜到它是如何实现的,但是来吧:我们是开发人员。我们不应该在猜测和假设上蒙混过关。例如,所有未来的实现都一样吗?其他平台的语言实现是否相同?这取决于语言的规范及其提供的保证。例如,未来或不同的平台实现(不是一个好的,但有可能)可能会在??实现中这样做:

return ReallyComplexFunction() == null ? 42 : ReallyComplexFunction();

ReallyComplexFunction那,如果它没有返回,就会调用两次null。(虽然这看起来是一个荒谬的实现,但如果你用一个可以为空的变量替换函数,它看起来很合理return a == null ? 42 : a:)

如上所述,我知道在我的测试中它只被调用一次,但我的问题是C# 规范是否保证/指定左侧只会被调用一次?如果有,在哪里?我在C# 语言规范中看不到任何这样的提及?运算符(我最初在其中寻找查询的答案)。

4

7 回答 7

9

运算符将??评估左侧一次,右侧为零或一次,具体取决于左侧的结果。

你的代码

int i = ReallyCleverFunction() ?? 42;

相当于(这实际上非常接近编译器实际生成的内容):

int? temp = ReallyCleverFunction();
int i = temp.HasValue ? temp.Value : 42;

或者更简单地说:

int i = ReallyCleverFunction().GetValueOrDefault(42);

不管你怎么看,它只ReallyCleverFunction被调用一次。

于 2013-11-12T14:05:03.747 回答
4

运算符与??左手无关。首先运行左手,然后??操作员评估其响应。

在您的代码中,ReallyCleverFunction只会运行一次。

于 2013-11-12T14:04:54.907 回答
0

它只会被调用一次。如果ReallyCleverFunction 的值为null,则使用值42,否则使用ReallyCleverFunction 的返回值。

于 2013-11-12T14:05:07.000 回答
0

它将评估函数,然后评估??运算符的左值(这是函数的结果)。它没有理由两次调用该函数。

于 2013-11-12T14:05:35.570 回答
0

它被调用一次并且按照文档我相信这应该足以假设它只被调用一次:

如果操作数不为空,则返回左侧操作数;否则返回正确的操作数。

?? 操作员

于 2013-11-12T14:06:47.240 回答
0

它只会运行一次,因为??操作符只是一个快捷方式

你的线

int i = ReallyCleverFunction() ?? 42;

是相同的

int? temp = ReallyCleverFunction();
int i;
if (temp != null)
{
    i = temp.Value;
} else {
    i = 42;
}

编译器完成了艰苦的工作。

于 2013-11-12T14:11:50.663 回答
0

首先,答案是肯定的,它确实保证它只会评估一次,通过官方 C# 语言规范第 7.13 节中的推断。

第 7.13 节始终将a其视为对象,因此它必须只接受函数的返回并在处理中使用它。它说以下关于?? 运算符(已添加重点):

• 如果b 是动态表达式,则结果类型是动态的。在运行时,首先评估 a。如果 a 不为 null,则将 a 转换为动态,这将成为结果。否则, b 被评估,这成为 result
• 否则,如果A 存在并且是可空类型并且存在从b 到A0 的隐式转换,则结果类型为A0。在运行时,首先评估 a。如果 a 不为 null,则将 a 解包为类型 A0,这将成为结果。否则,b 被求值并转换为 A0 类型,这成为结果。
• 否则,如果存在A 并且存在从b 到A 的隐式转换,则结果类型为A。在运行时,首先计算a。如果 a 不为空,则 a 成为结果。否则,b 被评估并转换为类型 A,这成为结果。
• 否则,如果b 的类型为B,并且存在从a 到B 的隐式转换,则结果类型为B。在运行时,首先计算a。如果 a 不为空,则将 a 解包为 A0 类型(如果 A 存在且可为空)并转换为 B 类型,这将成为结果。否则, b 被评估并成为结果。

作为旁注,问题末尾给出的链接不是 C# 语言规范,尽管它在“C# 语言规范”的 Google 搜索中排名第一。

于 2014-02-25T13:32:29.313 回答