16

我经常发现自己在做:

foo = foo ?? x;

为什么我不能这样做:

foo ??= x;

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

foo = foo + x;
4

14 回答 14

19

当我想到它时,

foo = foo ?? x 

真的只是

foo = foo != null ? foo : x

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

于 2009-02-17T18:07:09.640 回答
14

没有理由不能有这样的运算符,但我怀疑语言增加的复杂性虽然轻微,但超过了好处(我认为“非常轻微”)。

基本上,该语言的任何添加都有一个相当高的标准。你说你经常使用这个 - 多久一次,真的?虽然我认为??很方便,但我不能说我使用得非常频繁。

于 2009-02-17T18:07:51.230 回答
14

通常,C# 语言设计团队对添加新语法持保守态度。他们说,添加语言的价值必须与增加语言复杂性的成本进行权衡。

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

本文与以下问题特别相关??=

通常正确的设计决策是不改变任何东西。这可能是我从观看 Anders 在 C# 语言设计会议上学到的最重要的一课。通常会提出语言的一个领域,在该领域中似乎可以获得一些真正的收获。我们可以防止用户出现常见的编码错误,或者我们可以针对某个问题域提高语言的可用性。然后经过认真思考,通过所有解决问题的选项,答案是……什么都不做!即使问题是有效的,并且看起来我们应该能够添加一些东西来改善这种情况,但经过仔细考虑,没有办法解决问题,而成本不超过解决方案的收益。我见过 Anders 做出的许多最重要和最有价值的决定都是不增加语言复杂性的决定,除非增加的价值证明了复杂性是合理的。在边缘情况下,他几乎总是什么都不选择,而不是添加一些边缘的东西。

参考:

于 2009-02-17T18:57:46.647 回答
9

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

假设你有:

node = node.next;

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

node .= next;

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

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

add reg0, 1
mul reg1, 5

这些运算符的存在是“自然的”。

于 2009-02-17T18:45:24.900 回答
5

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

int? testValue;

return testValue ?? 0;

而不是像您的示例那样在分配操作中。此外,while+=保证在所有情况下都会修改 foo 的值,但+= 0不会??=

于 2009-02-17T18:06:09.017 回答
5

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

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

答:因为每个功能都以负 100 分开始,所以功能一开始不存在,必须有人来实现它们,如果他们添加了该功能,很可能这些资源已经花在对客户群有更大总体利益的事情上

...考虑设计该功能应如何工作所需的所有时间和精力,确定所有边界条件,然后对其进行编码,为其编写自动化测试,...编写文档和帮助文本,并继续维护功能预期生命周期的代码、测试和文档(在这种情况下可能是永远的)。所有这些资源是否都花在了对客户群有更大总体利益的事情上?(答案总是“是”——每个人和她的嫂子都能想办法完成这句话,“我不敢相信他们把所有时间都浪费在这个愚蠢的功能上而不是修复......” )

于 2009-02-17T19:04:00.783 回答
3

我看不出你为什么要使用 ?? 运算符自分配变量。

也许您是foo根据一些恰好是的数据库值进行设置的NULL,所以使用 ?? 该分配期间的运算符(消除了对 ??= 的需要):

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

相对于:

foo = (int?)rows["possiblyNullCount"];
foo = foo ?? 0;
于 2009-02-17T18:21:48.403 回答
3

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

于 2018-06-13T15:51:36.920 回答
2

主要是因为 +=、-= 等几乎都是事后才添加的,以保持与 C 和 C++ 的兼容性。(*) 因为 ?? 不是 C 或 C++ 的一部分,因此无需添加额外的运算符。

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

于 2009-02-17T18:09:04.690 回答
2

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

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;
    }
}

我没有花费大量时间思考这不起作用的可能方式,但它似乎确实通过了我的示例应用程序中的气味测试......

于 2009-02-17T18:37:59.067 回答
2

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

foo ?? foo = x;

如:

return foo ?? foo = x;

或(仅供说明!):

DoStuff( foo ?? foo = x );

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

于 2009-02-17T22:24:56.617 回答
1

这种风格的陈述感觉就像是来自属性 getter 的延迟加载。在这种情况下,我会选择这种语法

private Foo myFoo;
public Foo MyFoo
{
    get
    {
        return myFoo ?? (myFoo = new Foo());
    }
}
于 2009-02-17T18:19:49.860 回答
1

空合并赋值运算符??=是在 C# 8.0 中引入的

https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8#null-coalescing-assignment

于 2020-05-25T13:36:49.563 回答
-2

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

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

于 2009-02-17T18:05:06.540 回答