为什么不能在C#中加入空合并赋值运算符?
c#-8.0
空合并运算符
我最喜欢的 C# 特性之一是空合并运算符,我已经使用了很长时间:
// Simple fallback
var foo = specifiedValue ?? fallbackValue;
// Fetch if not present
foo = foo ?? getAFoo();
// Parameter validation
foo = foo ?? throw new ArgumentNullException(nameof(foo));
// Combination of the two previous examples
foo = foo ?? getAFoo() ?? throw new Exception("Couldn't track down a foo :( ");
空合并赋值运算符
我也喜欢新的 C# 8 运算符,它缩短了“如果不存在则获取”用例:
foo = foo ?? getAFoo(); // null-coalescing
foo ??= getAFoo(); // null-coalescing assignment
题
我曾希望也许我也可以在参数验证用例中使用空合并赋值运算符,但似乎不允许这样做。这就是我想做的:
foo = foo ?? throw new ArgumentNullException(nameof(foo)); // Does compile
foo ??= throw new ArgumentNullException(nameof(foo)); // Does not compile
谁能解释为什么空合并赋值运算符适用于“如果不存在则获取”场景而不适用于参数验证场景?
https://dotnetfiddle.net/W8cNPo
免责声明
我意识到这... ??= throw ...件事可能不是最易读的方法。我的问题与样式/可读性无关,因为它只是想了解这个运算符的一个怪癖。
谢谢!
回答
答案??很简单。它只是按照文档中所述的方式实现的:
空合并运算符 ?? 如果它不为空,则返回其左侧操作数的值;否则,它评估右侧操作数并返回其结果。这 ??如果左侧操作数的计算结果为非空,则运算符不会计算其右侧操作数。
的答案??= throw有点棘手。似乎这会很有用(或者从开发人员的角度来看可能是一致的),但这是有原因的。如果你深入到C#8.0空合并分配方案为??=运营商,你碰到这条线(加我的重点):
否则,a ??= b的类型是 A。a ??= b在运行时被评估为a ?? (a = b),除了 a 只计算一次。
这意味着您的作业将评估为
foo ?? (foo = throw new ArgumentNullException(nameof(foo)))
这在语法上无效。
他们必须那样实施吗?不,他们可以以不同的方式实施它,但他们没有。提案接着说这个
与任何语言功能一样,我们必须质疑语言的额外复杂性是否会通过提供给将从该功能受益的 C# 程序主体的额外清晰度来回报。
看起来在这里,额外的复杂性不被认为是有必要的,因为替代方案非常好。
借用 Julien 对该问题的评论(谢谢!),会议记录提供了更多背景信息
在右侧抛出表达式
是否应该允许以下情况:a ??= throw new Exception?现在只允许在某些地方使用 throw 表达式,因此我们必须明确添加支持。如果特征等价于 a = a ?? b 其中 b 是投掷,而不是 a ?? (a = b)。
结论
不支持