是否??运算符保证只运行左侧参数一次



例如,给定以下代码:

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# 语言规范中看不到任何此类提及?运算符(我最初寻找查询答案的地方)。

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

您的代码

int i = ReallyCleverFunction() ?? 42;

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

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

或者更简单地说:

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

无论哪种方式,ReallyCleverFunction只调用一次。

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

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

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

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

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

如果操作数

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

??算子

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

您的生产线

int i = ReallyCleverFunction() ?? 42;

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

编译器完成艰苦的工作。

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

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

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

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

最新更新