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

时间:2013-11-12 14:02:55

标签: c# .net

例如,给定此代码:

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# Language Specification for ?? operator(我最初寻找查询答案的地方)中看不到任何这样的提及。

7 个答案:

答案 0 :(得分:9)

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

您的代码

int i = ReallyCleverFunction() ?? 42;

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

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

或更简单:

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

无论你怎么看,ReallyCleverFunction只被召唤一次。

答案 1 :(得分:4)

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

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

答案 2 :(得分:0)

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

答案 3 :(得分:0)

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

答案 4 :(得分:0)

它被调用一次并且在文档之后我认为这应该足以假设它只被调用一次:

  

如果操作数不为空,则返回左侧操作数;除此以外   它返回正确的操作数。

?? operator

答案 5 :(得分:0)

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

你的行

int i = ReallyCleverFunction() ?? 42;

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

编译器做了很多工作。

答案 6 :(得分:0)

首先,答案是是的确保它只会评估一次,通过the official C# language specification第7.13节中的推断。

第7.13节始终将a视为对象,因此它必须仅返回函数并在处理中使用它。它说以下关于??运营商(重点补充):

  

•如果b是动态表达式,则结果类型是动态的。在运行时,首先评估a。 如果a不为null,则a将转换为dynamic,这将成为结果。否则,将评估b,这将成为结果   •否则,如果A存在并且是可空类型,并且从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存在并且可以为空)并转换为类型B,这将成为结果。否则,b被评估并成为结果。

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