How the right associative of null coalescing operator behaves?
null coalescing operator is right associative, which means an expression of the form
first ?? second ??third
is evaluated as
first ?? (second ?? third)
基于上述规则,我认为以下翻译不正确。
来自:
1 2 3 4 5 6 7 8 9
| Address contact = user.ContactAddress;
if (contact == null)
{
contact = order.ShippingAddress;
if (contact == null)
{
contact = user.BillingAddress;
}
} |
到:
1 2 3
| Address contact = user.ContactAddress ??
order.ShippingAddress ??
user.BillingAddress; |
相反,我认为以下是正确的(如果我错了请纠正我)
1 2
| Address contact = (user.ContactAddress ?? order.ShippingAddress) ??
user.BillingAddress; |
- 考虑到空合并运算符的正确关联性,我相信如果不使用一对左括号和右括号()来区分表达式计算的优先级,您的代码就永远无法成功地转换为使用空合并运算符。
这个规范实际上是自相矛盾的。
C 4规范第7.13节规定:
The null coalescing operator is right-associative, meaning that operations are grouped from right to left. For example, an expression of the form a ?? b ?? c is evaluated as a ?? (b ?? c).
另一方面,正如所指出的,7.3.1声称:
Except for the assignment operators, all binary operators are left-associative
我完全同意,对于简单的情况,你如何分组并不重要…但是,在某些情况下,如果操作数具有不同的类型,则隐式类型转换会执行有趣的操作,这可能真的很重要。
我会进一步考虑,Ping Mads和Eric,并为C的相关部分添加一个勘误表(这激发了这个问题)。
编辑:好吧,我现在有一个例子,它确实很重要……空合并运算符绝对是右关联的,至少在MS C_4编译器中是这样。代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| using System;
public struct Foo
{
public static implicit operator Bar (Foo input )
{
Console .WriteLine("Foo to Bar");
return new Bar ();
}
public static implicit operator Baz (Foo input )
{
Console .WriteLine("Foo to Baz");
return new Baz ();
}
}
public struct Bar
{
public static implicit operator Baz (Bar input )
{
Console .WriteLine("Bar to Baz");
return new Baz ();
}
}
public struct Baz
{
}
class Test
{
static void Main ()
{
Foo ? x = new Foo ();
Bar ? y = new Bar ();
Baz ? z = new Baz ();
Console .WriteLine("Unbracketed:");
Baz ? a = x ?? y ?? z ;
Console .WriteLine("Grouped to the left:");
Baz ? b = (x ?? y ) ?? z ;
Console .WriteLine("Grouped to the right:");
Baz ? c = x ?? (y ?? z );
}
} |
输出:
1 2 3 4 5 6 7 8
| Unbracketed:
Foo to Baz
Grouped to the left:
Foo to Bar
Foo to Bar
Bar to Baz
Grouped to the right:
Foo to Baz |
换言之,
行为与
但与
我不知道为什么在使用(x ?? y) ?? z时会有两个从foo到bar的转换-我需要更仔细地检查…
编辑:我现在还有一个问题要讨论双重转换…
- + 1,这是一个有趣的案例的一定的角落。我会更新我的答案是"权威"中的语句不具有"相同的"。
- "sixlettervariables甚至更多:它得到有趣的,真的。有一些真的很怪异的事情继续在自定义转换。我将在以后的文章的问题。
- 生成的细胞是空的检查在你的场景中。x奇复用)的多线索的"富贵来吧。"
- "sixlettervariables:是的,但我不确定它是正确的……
- 我同意。我能’t为什么它被认为是有用的输出。
- 好吧,有点不simpler测试的用户定义的转换。你有Animalsuppose类与类DogCat和衍生。你有三个变量,然后suppose Animal,DogCat和明显的,每个的编译时类型。然后用一个很好的表达(animal ?? cat) ?? dog将查找在普通型的基础上,将无法编译,因为animal ?? (cat ?? dog)猫和狗不是狗是猫,是不是。因此,在associativity of ??测验,如果你只是要看animal ?? cat ?? dog(带或不compiles在parentheses)。
乔恩的回答是正确的。
要清楚一点:c中的??操作符是右相关的。我刚刚检查了二进制运算符解析器,并验证了解析器是否将??视为右关联。
正如jon所指出的,规范既指出??操作符是右相关的,也指出除赋值之外的所有二进制操作符都是左相关的。由于规范本身矛盾,很明显只有一个是正确的。我将修改规范,以表示如下内容:
Except for the simple assignment, compound assignment and null coalescing operators, all binary operators are left-associative
更新:正如注释中所指出的,lambda运算符=>也是右相关的。
- 另一个问题就是,在读和已实现的正义,也=>算子是右结合。这是合法的,因为它的操作系统Func> f = x => y => 0;写有"隐式"parantheses向右。但当然,这不是一个"真正的",因为parentheses右到左associativity不会做是有意义的。所以我不知道,如果你认为这是一个额外的"异常"将要被添加到规范?
- 但也有x = y = 0(加成)与有意义的,它永远不会把parentheses到左,所以真的有差。如果是被称为=分配算子对联想,那么操作系统是=>lambda算子T的,不是吗?
- ntohl:"三元"的二元算子的算子。
- 杰普":"=>lambda算子"事实上是正确的),但我认为这是一个运营商。
- 汤姆:你的要求是一个lambda算子是算子是不安?我想你会发现,事实上是一个lambda算子的算子,因此名称"lambda算子。
- 汤姆:这是真的::更多的,往往不是我们认为的lambda算子的一种算子;显然,我忘了提到它的时候,这是书面的回答。这是很容易的,不想因为它是一operands算子表达并不一定是因为它不是以两个值和生产第三。但从透视的解析器,它只是另一个运营商的时候;当我们看到y = x => x + 1;的解析器需要能够工作,这parenthesizes y = (x => (x + 1));出什么样的和不nonsensical y = (x => x) + 1;或(y = x) => (x + 1);
- 汤姆:同样,我们通常认为的二元算子的.),虽然它是,我们通常想到Don’t的函数调用一个n元算子,但它是。
- 谢谢你的评论,"埃里克!我想这一切都取决于一个精确的定义使用对,但我认为最让义例是使用到一个运营商设置的东西,需要表达的表达和结果在一个operands是一些功能的评估采用的operands的评估值。有时,这种定义是stretched /短电路允许懒惰的评价。但它并没有被分配,或.=>。事实上,它能覆盖函数的调用,虽然。现在,所有适用于该程序的语义水平,这是一个关于我的思维。
- Eric:"但在解析器的水平,我想这的确让所有这些东西都是运营商的意义:不仅做他们所有的解析器非常同样的对待彼此,但事实上所有的解析器operands(甚至那些参与表达的东西不代表我们会呼叫一个在细胞中的表达本程序适用someth),和它的他们产生了对由此产生的表达。这样做的意义是什么?
- 汤姆:我想你但我注意点(1)和蛛网膜下腔出血(SAH)的表达x = y在线两端produces及其结果的价值,(2)蛛网膜下腔出血(SAH)的表达和x => y在线两端produces及其结果的价值,所以如果你想说:"你要表达的事情,运营商在线两端产生的结果的价值和一定的屁股"分配的lambda算子在这些案件和在会议上你的定义。
- 埃里克:是的东西",x到左或=>=)和在后者的情况下,也没有一个正确的表达方式,它是相同的或从左向右)+方式;例如,在评估结果的表达涉及到价值x)是非常不同的。另外,我们可以在左=>找到其他的东西(这是有效的,否则不表达(至少在#(7),如()和(x, y)。
- Eric:"我认为我们可以同意,有一些基本的差异之间的这些和其他的"运营商","正常"的运营商。我们也可以不同意,但事实上,它的目的是使人感到他们所有的运营商表主分类表。
我看不出这两者的重要性:
和
有同样的结果!
- 当他们的类型和ca,b是相同的。但在suppose类型A,B和C,有隐式的转换和从A到B和B到C,C,……然后发生了什么?看到我的答案)
- 乔恩:"这是我想到的问题,然后再决定着美国和它的失去。你是我的applaud挖掘和确定当前的observable associativity。
两者都按预期工作,并且有效地相同,因为表达式涉及简单类型(谢谢@jon skeet)。在您的示例中,它将从左到右链接到第一个非空值。
当将此运算符与具有不同优先级的运算符组合时,优先级(谢谢@ben voigt)更有趣:
1
| value = A ?? B ? C : D ?? E; |
基本上,关联性是通过运算符优先级或用户引入的子表达式(括号)内在地表示的。
- 我仍然认为在associativity问题,只有优先级。蛛网膜下腔出血(SAH)的三元算子的高优先级,因此它的A ?? (B ? C : D) ?? E:。。。。。。。这还无关紧要,这是(A ?? (B ? C : D) )?? E或A ?? ((B ? C : D) ?? E)
- 啊,请不要在任何码本所写的我将永远要读!!!!!!!!!!!!!!!是的,我是你的唯一,你会illustrating点。
- 解距离模糊的horribly + 1的那一片代码,希望不会,我可以看到光的制造。
- 本:我认为"我与你在这一个。"你从来没有在乎associativity"时,解析器只是写作规则,优先级。很好的抓。
- 疯狂代码是可怕的。
- @本:它在MSDN阅读列表看起来像是高优先级,?:??比蛛网膜下腔出血。
- "sixletter:哦,可恶的是:我期待到忘了检查和管理:(在浏览器标签。然后,它的运作和在相邻的(A ?? B)? C : (D ?? E)有平等的优先级规则,是不是操作系统的associativity甚至应用。
- 本:它的好,"我认为我们所有的协议是有效的。问题是相同的,由于我可能要考虑语境和外码提示,这样的后台是horrific说明优先级。
- "sixletter:"有没有其他方式比confusing优先级代码和说明,没有其他代码使用的优先级比confusing(插图)和动机是不是严格必要的,甚至当添加parentheses)。
- "sixlettervariables:他们再不相同时,不同的类型是有效的参与和转换。看到我的答案。