CodeGo.net>如何确切地解释+ =和-=运算符?

myCol-=运算符到底是做什么的?

还是它们是隐式的,因为它们是按类型定义的?

我已经广泛使用了它们,这是语法的一个非常简单的功能,但是我从未想过它的工作原理。

问题产生了什么

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

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

一切都很好。 但是,为什么这不适用于收藏夹呢?

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

您可能会说:“您正在尝试附加其他类型,不能将字符串附加到非字符串类型中”。 但是以下方法也不起作用:

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

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

myButton.Click += myButton_Click;

我显然对这些操作员的工作方式缺乏深入的了解。

请注意:我不是在实际项目中尝试以此方式构建集合myCol。 我只是对这个运算符的运作感到好奇,这是假设的。

user1306322 asked 2020-08-12T02:00:08Z
4个解决方案
41 votes

+=运算符的隐式定义如下:-=变为+,与-运算符相同。
(caveat:正如Jeppe所指出的,如果+=是一个表达式,则仅当您使用-=时才被评估一次,而对于+则被两次评估)

您不能单独重载+=-=运算符。 任何支持+运算符的类型也都支持-。您可以通过重载+=-=,将对+=-=的支持添加到您自己的类型中。

但是,您发现了一个硬编码到c#中的异常:
事件具有+=-=运算符,该运算符将事件处理程序添加到已订阅的事件处理程序列表中并从中删除。 尽管如此,它们不支持+-运算符。
对于常规的运算符重载,您无法为自己的类执行此操作。

HugoRune answered 2020-08-12T02:00:40Z
28 votes

就像另一个答案说的那样,未为+定义+运算符。您可以检查它以使其过载,编译器将抛出此错误One of the parameters of a binary operator must be the containing type

但作为实验,您可以定义自己的类,继承+并定义+运算符。 像这样:

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

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

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

编辑

根据@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;
}
Pikoh answered 2020-08-12T02:01:27Z
15 votes

简短的答案是,对于给定的类型,必须在C#中重载运算符。 这也适用于List<T>string包含此运算符的重载,但List<>却没有。 因此,无法将+=运算符用于列表。 对于代表,+=运算符也被重载,这就是为什么您可以在事件处理程序上使用+=的原因。

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

从技术上讲,您并不是真正使+=-操作符过载,而是让3007483813678285885825操作符过载。 然后,通过将+运算符与一个赋值相结合来推断+=运算符。 为此,应以使结果类型与第一个参数的类型匹配的方式重载30074838136782782858运算符,否则当您尝试使用+=时,C#编译器将引发错误消息。

Georg answered 2020-08-12T02:01:59Z
4 votes

正确的实现实际上比人们想象的要复杂得多。 首先,仅说+=-=完全相同是不够的。在最简单的情况下,它具有相同的语义,但它不是简单的文本替换。

首先,如果左侧的表达式比简单变量复杂,则仅对它求值一次。 因此+=-=不同,因为它将在与获取对象完全不同的对象上分配值,或者将导致该方法的副作用发生两次。

如果+=返回引用类型,则可以将复合赋值运算符视为-=(但仍为表达式)。 但是,如果+=是值类型,则在该方法返回引用(C#7中的新增功能)或它实际上是数组元素或从索引器返回的内容等情况下,这种简化也将不起作用。 运算符可确保它制作的副本不超过修改该对象所需的副本,并且它将被应用到正确的位置,并且没有其他副作用。

不过,事件分配是完全不同的野兽。 在类范围之外,+=导致调用添加访问器,而-=导致调用事件的删除访问器。 如果这些访问器不是由用户实现的,则事件分配可能会导致在类作用域内的内部委托对象上调用Delegate.Combine和Delegate.Remove。 这就是为什么不能将事件对象简单地带到类之外的原因,因为它不是公共的。 +=/-=在这种情况下也不是表达式。

我建议阅读Eric Lippert的《化合物分配》。 它对此进行了更详细的描述。

IllidanS4 answered 2020-08-12T02:03:04Z
translate from https://stackoverflow.com:/questions/40503509/how-exactly-can-and-operators-be-interpreted