为什么我不能做?=在C#中?

我经常发现自己在做:

foo = foo ?? x; 

为什么我不能这样做:

 foo ??= x; 

编辑 :我知道这不是语言的一部分……我的问题是“为什么不”? 我发现重复“foo”的必要性令人不愉快并且可能容易出错。 它看起来像丑陋一样:

 foo = foo + x; 

通常,C#语言设计团队对添加新语法很保守。 他们说,必须权衡语言增加的价值与语言复杂性增加的代价。

Peter Hallam有一段时间是C#编译器开发负责人,也是C#语言设计团队的成员。 他写了一篇关于测量新function的方法,称为Yardstick ,尽管他更关注交互式GUIfunction而不是语言function。

本文与??=的问题特别相关:

通常,正确的设计决策是不改变任何东西。 这可能是我在C#语言设计会议上观看Anders时学到的最重要的一课。 通常会提出一种语言领域,其中可能会产生一些真正的收益。 我们可以防止用户出现常见的编码错误,或者我们可以提高某个问题域的语言可用性。 在经过深思熟虑之后,通过所有解决问题的方案,答案就是……没事! 即使问题是有效的,看起来我们应该能够添加一些东西来改善这种情况,但经过仔细的反思后,没有办法解决不超过解决方案收益的问题。 我看到Anders做出的许多最重要和最有价值的决定都是决定不增加语言的复杂性,除非增加的价值certificate了复杂性。 在边缘情况下,他几乎总是选择添加一些边缘的东西。

参考文献:

  • 码尺
  • 程序员真正做了什么?

当我想到它时,

 foo = foo ?? x 

真是公正

 foo = foo != null ? foo : x 

在这一点上,+ =的类比开始分崩离析。

没有理由不能有这样的运营商,但我怀疑语言的复杂程度虽然微不足道,但却超过了利益(我认为“非常轻微”)。

基本上任何语言的添加都有很高的清晰度。 你说你经常使用这个 – 经常,真的吗? 虽然我认为?? 方便,我不能说我甚至经常使用它。

?? 它不是一个“运算符”,因为它使用操作数的值进行“操作”。 您应该将其视为语言构造

假设你有:

 node = node.next; 

那么您是否希望能够执行以下操作?

 node .= next; 

我认为??=不存在的原因与.=不存在相同。

此外,像+=*=等的一元运算符在汇编级别具有直接对应的运算符。 伪汇编:

 add reg0, 1 mul reg1, 5 

这些运营商的存在只是“自然”。

没有操作员执行此操作。 但是,对于该语言的未来版本,这是一个有趣的建议。 我怀疑到目前为止还没有包括它,因为聚结操作符的主要用例是?? ,使用Nullable类型并获取值,如:

 int? testValue; return testValue ?? 0; 

而不是像你的例子那样的赋值操作。 此外,虽然+=保证在所有情况下都修改foo的值,但+= 0??=不会。

在讨论??= to +=的类比是否有意义时,每个人都缺少一个更简单的答案。

问题:为什么你不能做foo ??= x; 在C#?

答:因为每个function都以负100分 开始 ,所以function开始不存在,有人必须让它们发生,并且最有可能的是,如果他们添加了该function, 那些资源已用于对客户群有更大总收益的事情 :

…想想设计function应该如何工作所需的所有时间和精力,确定所有边界条件,然后对其进行编码,为其编写自动化测试,…编写文档和帮助文本,并继续维护function预期寿命的代码,测试和文档(在这种情况下可能是永久的)。 是否所有这些资源都花在了对客户群有更大利益的事情上? (对此的回答总是“是” – 每个人和她的嫂子都能找到完成判决的方法,“我不敢相信他们一直在浪费这个愚蠢的特征而不是修复……” )

我没有看到为什么你会使用??的原因很多? 运算符自我赋值变量。

也许你根据一些碰巧为NULL数据库值设置foo ,所以使用??更有意义? 该赋值期间的运算符(不需要?? =):

 foo = (int?)rows["possiblyNullCount"] ?? 0; 

而不是:

 foo = (int?)rows["possiblyNullCount"]; foo = foo ?? 0; 

主要是因为+ =, – =等几乎被添加,以保持与C&C ++的兼容性。(*)因为?? 不是C或C ++的一部分,不需要添加额外的运算符。

(*)请注意,在C ++中,为类定义运算符时,通常会定义operator + =(),然后基于它实现operator +()。 (这通常是最有效的方式)。 但是,在C#中,一个实现operator +,编译器会根据oper +自动添加operator + =。 这就是为什么我说+ =运算符是事后补充的。

虽然不完全是你要求的(它不是?? =)……你也许可以利用扩展方法。

 static void Main(string[] args) { object foo = null; object x = "something"; Console.WriteLine(foo.NullToValue(x)); } public static class ObjectExtensions { public static object NullToValue(this object obj, object value) { return obj != null ? obj : value; } } 

我没有花费大量时间考虑可行的方法,但这似乎在我的示例应用程序中通过了气味测试……

我也很想念它 – Ruby毁了我。 这是一个类似的构造,您可以在表达式中使用(如果您对副作用不过敏):

 foo ?? foo = x; 

如:

 return foo ?? foo = x; 

或(仅供参考!):

 DoStuff( foo ?? foo = x ); 

在属性getter之外使用这种模式可能不是一个好主意。

2017年更新 :Null-coalescing assignment是C#语言设计团队正在考虑的一项活跃提案。 请通过https://github.com/dotnet/csharplang/issues/34投票或加入讨论

这种风格的陈述感觉就像是财产吸气者的懒惰。 在这种情况下,我会选择这种语法

 private Foo myFoo; public Foo MyFoo { get { return myFoo ?? (myFoo = new Foo()); } } 

因为C#中没有这样的?? =运算符。

虽然+ =可能看起来像两个运算符用不同的语法表示它只是一个运算符。