【问题标题】:Why can't you throw in a null-coalescing assignment operator in C#?为什么不能在 C# 中加入空合并赋值运算符?
【发布时间】:2021-04-29 16:03:04
【问题描述】:

空合并运算符

我最喜欢的 C# 功能之一是 null-coalescing 运算符,我已经使用了很长时间:

// 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

问题

我曾希望也许我也可以在参数验证用例中使用 null-coalescing 赋值运算符,但似乎不允许这样做。这就是我想做的:

foo = foo ?? throw new ArgumentNullException(nameof(foo)); // Does compile
foo ??= throw new ArgumentNullException(nameof(foo));  // Does not compile

谁能解释为什么 null-coalescing 赋值运算符适用于“如果不存在则获取”场景而不适用于参数验证场景?

https://dotnetfiddle.net/W8cNPo

免责声明

我意识到... ??= throw ... 这件事可能不是最易读的方法。我的问题不是关于样式/可读性,而是试图理解这个运算符的一个怪癖。

谢谢!

【问题讨论】:

  • 会“因为它不是为了这样做吗?”一个可以接受的答案?
  • 有点模糊,也许 :) 我只是好奇,因为我认为这种行为与 ??操作员,所以我很惊讶地看到它们在这种情况下不能类似地工作。我不知道这是否指向我不知道的一些根本差异,这可能会产生其他有助于了解的含义。

标签: c#-8.0


【解决方案1】:

?? 的答案相当简单。它只是按照documentation 中所述的方式实现的:

空合并运算符 ??如果不为空,则返回其左侧操作数的值;否则,它计算右手操作数并返回其结果。这 ??如果左侧操作数的计算结果为非空,则运算符不会计算其右侧操作数。

??= throw 的答案有点棘手。似乎它会很有用(或者从开发人员的角度来看可能是一致的),但这是有原因的。如果您深入了解 ??= 运算符的 C# 8.0 Null Coalescing Assignment proposal,您会遇到这一行(我的重点是添加):

否则,a ??= b 的类型为 A。a ??= b 在运行时被评估为 a ?? (a = b),除了 a 只计算一次。

这意味着您的作业将评估为

foo ?? (foo = throw new ArgumentNullException(nameof(foo)))

在语法上无效。

他们必须以这种方式实施吗?不,他们本可以以不同的方式实施它,但他们没有。提案继续这样说

与任何语言功能一样,我们必须质疑语言的额外复杂性是否可以通过为将从该功能中受益的 C# 程序主体提供的额外清晰度得到回报。

看起来像这里,额外的复杂性被认为是不合理的,因为替代方案非常好。

借用 Julien 的 cmets 关于这个问题(谢谢!),meeting notes 提供了更多上下文

在右侧抛出表达式

是否应该允许:a ??= throw new Exception? throw 表达式现在只允许在某些地方使用,因此我们必须显式添加支持。如果该功能等效于 a = a ?? b 其中 b 是投掷,而不是 a ?? (a = b)。

结论

不支持

【讨论】:

  • 一个很好的答案——正是我所希望的。我同意从开发人员的角度来看这很不直观,但很高兴理解为什么它不能以他们选择的实现方式工作。
猜你喜欢
  • 1970-01-01
  • 2013-03-17
  • 1970-01-01
  • 2021-08-29
  • 2010-10-13
  • 1970-01-01
  • 2021-02-28
  • 1970-01-01
相关资源
最近更新 更多