How EXACTLY can the operator + = and - = be interpreted?

What exactly (under the hood) do the += and -= operators do?

Or are they implicit in the fact that they are defined for each type?

I used them extensively, this is a very simple syntax feature, but I never thought about the depths of how this works.

What caused the question

I can bind the string value as follows:

 var myString = "hello "; myString += "world"; 

All perfectly. But why does this not work with collections?

 var myCol = new List<string>(); myCol += "hi"; 

You can say: "It's good that you are trying to add another type, you cannot add a string to a type that is not a string." But the following does not work:

 var myCol = new List<string>(); myCol += new List<string>() { "hi" }; 

Well, maybe it doesn't work with collections, but is () a collection of event handlers?

 myButton.Click += myButton_Click; 

I clearly lack a deep understanding of how these operators work.

Please note: I am not going to create myCol collection this way in a real project. I'm just wondering how this operator works, it's hypothetical.

+43
operators c #
Nov 09 '16 at 9:24
source share
4 answers

The operator += implicitly defined as follows: a += b turns into a = a + b; , the same with the -= operator.
(caveat: as Jeppe pointed out that if a is an expression, it is evaluated only once if you use a+=b , but twice with a=a+b ) sub>

You cannot overload the += and -= operator separately. Any type that supports the + operator also supports += . You can add support += and -= to your own types of overload + and - .

However, there is one exception, hard coded in C #, that you find:
Events have a += and -= operator, which adds and removes an event handler to the list of handlers for signed events. Despite this, they do not support the + and - operators.
This is not something you can do for your own classes with regular operator overloading.

+41
Nov 09 '16 at 9:33
source share

As another answer says, the + operator is not defined for List<> . You can check it by trying to overload it, the compiler will throw this error One of the parameters of a binary operator must be the containing type .

But as an experiment, you can define your own class that inherits from List<string> and define the + operator. Something like that:

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

Then you can do it without problems:

 StringList listString = new StringList() { "a", "b", "c" }; StringList listString2 = new StringList() { "d", "e", "f" }; listString += listString2; 

Edit

In the @EugeneRyabtsev comment, my implementation of the + operator will lead to unexpected behavior. So it should be something like this:

 public static StringList operator +(StringList lhs, StringList rhs) { StringList newList=new StringList(); newList.AddRange(lhs.ToArray<string>()); newList.AddRange(rhs.ToArray<string>()); return newList; } 
+28
Nov 09 '16 at 9:52
source share

The short answer is that statements in C # must be overloaded for a given type. This is also true for += . string contains an overload of this statement, but List<> does not. Therefore, using the += operator for lists is not possible. For delegates, the += operator += also overloaded, so you can use += for event handlers.

A slightly longer answer is that you can overload the operator yourself. However, you will have to overload it for your own types, so creating an overload for List<T> not possible, while you can really do it for your own class, which, for example, inherits from List<T> .

Technically, you really do not overload the += operator, but the + operator. The += operator += then output by combining the + operator with the destination. For this to work, the + operator must be overloaded so that the type of the result matches the type of the first argument, otherwise the C # compiler is going to give an error message when trying to use += .

+15
Nov 09 '16 at 9:29
source share

The correct implementation is actually quite complicated than you might think. First of all, it is not enough to say that a += b exactly matches a = a+b . It has the same semantics in the simplest case, but it is not a simple text replacement.

First, if the expression on the left is more complex than a simple variable, it is evaluated only once. Thus, M().a += b does not coincide with M().a = M().a + b , since this will assign a value to a completely different object than it was accepted, or cause side effects of the method twice.

If M() returns a reference type, the compound assignment operator can be represented as var obj = M(); obj.a = obj.a+b; var obj = M(); obj.a = obj.a+b; (but still being an expression). However, if obj had a value type, this simplification would also not work if the method returned a link (new in C # 7) or if it was actually an array element or something returned from an indexer, etc. the operator guarantees that he does not make more copies than is necessary to change the object, and he will be applied to the right place without additional side effects.

The purpose of the events is a completely different beast. Outside the class , += causes the add accessor to be called, and -= causes the remove accessor event to be called. If these accessors are not implemented by the user, event assignment can result in a call to Delegate.Combine and Delegate.Remove for the internal delegate object inside the class scope. This is why you cannot just get an event object outside the class because it is not publicly available. += / -= also not an expression in this case.

I recommend reading the Compound Assignment by Eric Lippert. He describes this in much more detail.

+4
Nov 09 '16 at 11:50
source share



All Articles