例如,给定此代码:
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(我最初寻找查询答案的地方)中看不到任何这样的提及。
答案 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)
答案 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#语言规范”。