为什么微软没有为StringBuilder重载+=运算符?

8

对于StringBuilder类,为什么不重载+=运算符,而是使用独特的.Append()方法呢?

.Append()方法只能将字符串连接起来,那么为什么他们不直接重载+=运算符呢:

StringBuilder sb = new StringBuilder();
sb += "My string";

这是效率的问题吗? 还是传统或直觉的问题?

谢谢,


1
因为...那不就跟字符串一样了吗?这就像是问为什么List没有+=来添加一个对象... - Shahar
那么为什么要有一个StringBuilder类呢? - PeonProgrammer
3
我想让我的评论暗示我对Shahar的例子有多不满意。 - PeonProgrammer
2
@PeonProgrammer - string += string 不是字符串连接。它是连接和赋值。由于字符串是不可变的,所以 string += string 会创建一个新的字符串,该字符串是两个字符串连接在一起,然后将原始字符串变量覆盖为这个新字符串。另一方面,Stringbuilder 是可变字符串操作,因此 .Append() 不会创建一个新字符串来替换旧的字符串... 如果这样做将使 Stringbuilder 的好处失效。所以你的问题基本上是,为什么 Stringbuilder 不像一个字符串?答案是因为它不是一个字符串,它是一个 Stringbuilder。 - Erik Funkenbusch
@Shahar - 虽然我同意你的观点,但框架确实有几个这样做的例子。例如,事件处理程序使用+=来将对象添加到其列表中,使用-=从列表中删除对象。语言设计师在过去的几年中做出了一些值得质疑的选择。 - Erik Funkenbusch
2
你得到了我的问题点赞,因为你的问题对于新程序员理解Eric Lippert的答案非常重要。太多次遇到新程序员犯这种错误了。 - Orel Eraki
1个回答

30

算术运算应仅限于行为类似于算术值的类型。两个字符串的总和就已经够糟糕的了,将加法操作与字符串串联混淆是一个有问题的选择,因为字符串串联遵守的规则很少; 特别是,a + b != b + a

但是对于 可变状态 而不是 算数值 定义的字符串 构建器,这种混淆实在太糟糕了。 两个东西的总和应该是第三个与两个加数不同的东西。也就是说,a += b 必须a = a + b 具有相同语义,而不是 a.MutateWith(b)。如果最后没有对 a 进行赋值,则复合赋值运算符就是错误的运算符。

更一般地说:永远不要做可爱的运算符重载。运算符重载是为了使两个复杂的数字相加得到第三个数字,而不是为了让一个客户加上一罐花生酱等于购买订单或其他愚蠢的事情。


7
能否解释一下为什么 C# 使用 += 和 -= 向事件处理程序添加项目呢? ;) - Erik Funkenbusch
1
@ErikTheViking 说实话,在事件处理程序中使用 += 确实会产生一个新的委托。委托是不可变的,所以 a += b 实际上会将一个新的组合委托分配给 a。我承认这并不理想,但至少它遵循了 Eric 设定的最大规则。 - dlev
3
@dlev所说的是正确的。就像+被选择表示字符串的连接一样令人遗憾,同样不幸的是+在委托中表示顺序组合。但是,就像字符串一样,两个委托可以相加得到第三个。当您在委托上使用+=时,它确实具有a = a + b的语义。但我从来没有喜欢过C#的这个特性,它对我来说似乎太过可爱了。 - Eric Lippert
1
@silkfire:但是我们可以编写一个更有效的Complex * double用户定义运算符,只需将实部和虚部乘以double即可;这是两个乘法。如果没有这个,我们必须先通过调用转换器来创建Complex(1.5 + 0i),然后执行通常的四个乘法和两个加法来将两个复数相乘。通过拥有一个特殊目的的用户定义运算符,在这种常见情况下,我们可以节省一半以上的工作。 - Eric Lippert
2
此外,将矩阵乘以标量得到新矩阵也是很常见的操作。 - Brian
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接