怎样才能解释+ =和 - =运算符?

42 c# operators

正是(引擎盖下)做了什么+=-=运营商呢?

或者它们是隐含的,因为它们是按类型定义的?

我已广泛使用它们,这是语法的一个非常简单的特性,但我从未想过它的工作原理的深度.

关于这个问题带来了什么

我可以像这样连接一个字符串值:

var myString = "hello ";
myString += "world";
Run Code Online (Sandbox Code Playgroud)

一切都很好.但为什么这不适用于收藏?

var myCol = new List<string>();
myCol += "hi";
Run Code Online (Sandbox Code Playgroud)

你可能会说'你正试图附加一个不同的类型,你不能将一个字符串附加到一个非字符串的类型'.但以下情况也不起作用:

var myCol = new List<string>();
myCol += new List<string>() { "hi" };
Run Code Online (Sandbox Code Playgroud)

好吧,也许它不适用于集合,但以下不是一种(某种)事件处理程序集合?

myButton.Click += myButton_Click;
Run Code Online (Sandbox Code Playgroud)

我显然缺乏对这些运算符如何工作的深入理解.

请注意:myCol在实际项目中,我不是试图以这种方式构建集合.我只是对这个运营商的运作感到好奇,这是假设的.

Hug*_*une 41

+=被隐式这样定义操作:a += b变成a = a + b;,同时与-=运营商.
(警告:正如Jeppe指出的那样,如果a是一个表达式,它只会被评估一次,如果你使用a+=b,但两次a=a+b)

您不能单独重载+=-=运算符.任何支持+运营商的类型也支持+=.您可以添加的支持+=,并-=以自己的类型由超载+-.

然而,有一个异常硬编码到c#中,您已经发现:
事件有一个+=-=运算符,它将事件处理程序添加到已订阅的事件处理程序列表中.尽管如此,他们并不支持+-运营商.
对于具有常规运算符重载的自己的类,这不是您可以做的事情.

  • 通常需要注意的是,`+ =`的左侧仅被评估一次.因为`CallMethod().成员+ = 10;`与`CallMethod()不完全相同.成员= CallMethod().成员+ 10;`因为前者`CallMethod`只被调用一次,而对于后者,它被调用两次. (21认同)
  • @SamC我认为在= +运算符和使用赋值运算符后跟一元+运算符之间也不明确.如果"a = + b"表示"a = a + b"或"a =(+ b)",编译器将如何知道? (3认同)

Pik*_*koh 28

正如另一个答案所说,+运营商没有定义List<>.您可以检查它是否尝试重载它,编译器会抛出此错误One of the parameters of a binary operator must be the containing type.

但作为实验,您可以定义自己的类继承List<string>并定义+运算符.像这样的东西:

class StringList : List<string>
{
    public static StringList operator +(StringList lhs, StringList rhs)
    {
        lhs.AddRange(rhs.ToArray<string>());
        return lhs;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以毫无问题地做到这一点:

StringList listString = new StringList() { "a", "b", "c" };
StringList listString2 = new StringList() { "d", "e", "f" };
listString += listString2;
Run Code Online (Sandbox Code Playgroud)

编辑

根据@EugeneRyabtsev评论,我对+运算符的实现会导致意外行为.所以它应该是这样的:

public static StringList operator +(StringList lhs, StringList rhs)
{
      StringList newList=new StringList();
      newList.AddRange(lhs.ToArray<string>());
      newList.AddRange(rhs.ToArray<string>());
      return newList;
}
Run Code Online (Sandbox Code Playgroud)

  • 可能与作者的期望相反,`listString1`将被更改,并且随后对`listString3`的任何后续修改都会更改,因为它们将是相同的列表(List <>是一个类).无法确定下一个人是否会期待这一点,即使是你所期待的. (6认同)
  • 欢迎提到为什么`+ =`比`+'更好的原语:用'+ =`写`+'不需要任何费用,用'+'写`+ ='需要不必要地重复lhs.很难成为C#. (3认同)
  • 这是一个危险的实验,在某种意义上说,如果你习惯在生产中做这样的事情,那么其他人做的另一件事就是写`listString3 = listString1 + listString2;`并猜测会发生什么. (2认同)

Geo*_*org 15

简短的回答是C#中的运算符必须为给定类型重载.这也适用+=.string包含此运算符的重载,但List<>尚未包含.因此,+=无法使用运算符列表.对于代理,+=操作员也会过载,这就是您可以+=在事件处理程序上使用的原因.

稍微长一点的答案是您可以自己使操作员过载.但是,您必须为自己的类型重载它,因此List<T>无法创建重载,而实际上您可以为自己的类(例如继承)执行此操作List<T>.

从技术上讲,你并没有真正超载+=-operator,而是+操作员.该+=操作随后被合并推断+操作与分配.为此,+操作符应该以结果类型与第一个参数的类型匹配的方式重载,否则C#-compiler将在您尝试使用时抛出错误消息+=.

  • @JᴀʏMᴇᴇ一般没有添加/附加的通用概念 (4认同)