C#运算符重载为`+ =`?

我正在尝试为+=做操作符重载,但是我不能。 我只能使运算符超载+

怎么来的?

编辑

这是不工作的原因是我有一个Vector类(与X和Y领域)。 考虑下面的例子。

 vector1 += vector2; 

如果我的运营商超载设置为:

 public static Vector operator +(Vector left, Vector right) { return new Vector(right.x + left.x, right.y + left.y); } 

然后结果将不会被添加到vector1中,而是vector1也将通过引用成为一个全新的Vector。

可重载操作符 ,从MSDN:

赋值运算符不能被重载,例如+= ,则用+来评估,这可能会超载。

更重要的是,任何赋值操作符都不会超载。 我认为这是因为垃圾收集和内存pipe理将会产生影响,这是CLR强types世界中潜在的安全漏洞。

不过,让我们看看究竟是一个运营商。 根据着名的杰弗里·里克特(Jeffrey Richter)的着作 ,每种编程语言都有自己的操作符列表,这些列表是用特殊的方法调用编译的,而CLR本身对操作符却一无所知。 那么让我们来看看究竟在++=运算符后面留下了什么。

看到这个简单的代码:

 Decimal d = 10M; d = d + 10M; Console.WriteLine(d); 

让我们来看看这个指令的IL代码:

  IL_0000: nop IL_0001: ldc.i4.s 10 IL_0003: newobj instance void [mscorlib]System.Decimal::.ctor(int32) IL_0008: stloc.0 IL_0009: ldloc.0 IL_000a: ldc.i4.s 10 IL_000c: newobj instance void [mscorlib]System.Decimal::.ctor(int32) IL_0011: call valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::op_Addition(valuetype [mscorlib]System.Decimal, valuetype [mscorlib]System.Decimal) IL_0016: stloc.0 

现在让我们看看这个代码:

 Decimal d1 = 10M; d1 += 10M; Console.WriteLine(d1); 

而IL代码为:

  IL_0000: nop IL_0001: ldc.i4.s 10 IL_0003: newobj instance void [mscorlib]System.Decimal::.ctor(int32) IL_0008: stloc.0 IL_0009: ldloc.0 IL_000a: ldc.i4.s 10 IL_000c: newobj instance void [mscorlib]System.Decimal::.ctor(int32) IL_0011: call valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::op_Addition(valuetype [mscorlib]System.Decimal, valuetype [mscorlib]System.Decimal) IL_0016: stloc.0 

他们是平等的! 所以+=运算符只是C#中程序的语法糖,你可以简单地重载+运算符。

例如:

 class Foo { private int c1; public Foo(int c11) { c1 = c11; } public static Foo operator +(Foo c1, Foo x) { return new Foo(c1.c1 + x.c1); } } static void Main(string[] args) { Foo d1 = new Foo (10); Foo d2 = new Foo(11); d2 += d1; } 

此代码将被编译并成功运行为:

  IL_0000: nop IL_0001: ldc.i4.s 10 IL_0003: newobj instance void ConsoleApplication2.Program/Foo::.ctor(int32) IL_0008: stloc.0 IL_0009: ldc.i4.s 11 IL_000b: newobj instance void ConsoleApplication2.Program/Foo::.ctor(int32) IL_0010: stloc.1 IL_0011: ldloc.1 IL_0012: ldloc.0 IL_0013: call class ConsoleApplication2.Program/Foo ConsoleApplication2.Program/Foo::op_Addition(class ConsoleApplication2.Program/Foo, class ConsoleApplication2.Program/Foo) IL_0018: stloc.1 

更新:

根据你的更新 – 作为@EricLippert说,你真的应该有作为一个不可变对象的载体。 两个vector相加的结果是一个新的vector,而不是第一个大小不同的vector。

如果由于某种原因需要更改第一个向量,则可以使用此重载(但对于我来说,这是非常奇怪的行为):

 public static Vector operator +(Vector left, Vector right) { left.x += right.x; left.y += right.y; return left; } 

这是因为赋值运算符不能被重载的原因。 您无法编写正确执行分配的代码。

 class Foo { // Won't compile. public static Foo operator= (Foo c1, int x) { // duh... what do I do here? I can't change the reference of c1. } } 

赋值运算符不能被重载,例如+ =,则用+来评估,这可能会超载。

来自MSDN 。

我想你会发现这个链接的信息:可重载操作符

赋值运算符不能被重载,例如+ =,则用+来评估,这可能会超载。

你不能重载+=因为它不是一个独特的操作符,它只是语法糖 。 x += y只是写x = x + y的简写方式。 因为+=是用+=运算符定义的,所以在x += yx = x + y行为不完全相同的情况下,允许您单独覆盖它可能会产生问题。

在较低的级别上,C#编译器很可能会将这两个expression式编译为相同的字节码,这意味着运行时很可能在程序执行期间不能以不同的方式对待它们。

我可以理解,你可能想把它当作一个单独的操作来处理:在像x += 10这样的语句中,你知道你可以改变x对象的位置,也许会节省一些时间/内存,而不是创build一个新的对象x + 10之前分配在旧的参考。

但是考虑这个代码:

 a = ... b = a; a += 10; 

应该在最后? 对于大多数types,不, ab多10。 但是,如果你可以重载+=运算符来适应变化,那么是的。 现在认为ab可以传递到程序的很远的部分。 如果您的对象开始更改代码所不期望的位置,则可能的优化可能会产生令人困惑的错误。

换句话说,如果性能非常重要,用x.increaseBy(10)这样的方法调用x += 10并不难,而且对于每个参与者来说都更加清晰。

这是因为这个操作符不能被重载:

赋值运算符不能被重载,例如+ =,则用+来评估,这可能会超载。

MSDN

只是超载+运营商,因为

x += y等于x = x + y

如果你像这样超载+运算符:

 class Foo { public static Foo operator + (Foo c1, int x) { // implementation } } 

你可以做

  Foo foo = new Foo(); foo += 10; 

要么

  foo = foo + 10; 

这将编译和运行平等。

+=运算符中使用+=运算符超载, A += B等于A = operator+(A, B)

对于这个问题总是有相同的答案:为什么你需要+= ,如果你超负荷的话,免费得到它。 但是如果我有这样的课程会发生什么事情。

 using System; using System.IO; public class Class1 { public class MappableObject { FileStream stream; public int Blocks; public int BlockSize; public MappableObject(string FileName, int Blocks_in, int BlockSize_in) { Blocks = Blocks_in; BlockSize = BlockSize_in; // Just create the file here and set the size stream = new FileStream(FileName); // Here we need more params of course to create a file. stream.SetLength(sizeof(float) * Blocks * BlockSize); } public float[] GetBlock(int BlockNo) { long BlockPos = BlockNo * BlockSize; stream.Position = BlockPos; using (BinaryReader reader = new BinaryReader(stream)) { float[] resData = new float[BlockSize]; for (int i = 0; i < BlockSize; i++) { // This line is stupid enough for accessing files a lot and the data is large // Maybe someone has an idea to make this faster? I tried a lot and this is the simplest solution // for illustration. resData[i] = reader.ReadSingle(); } } retuen resData; } public void SetBlock(int BlockNo, float[] data) { long BlockPos = BlockNo * BlockSize; stream.Position = BlockPos; using (BinaryWriter reader = new BinaryWriter(stream)) { for (int i = 0; i < BlockSize; i++) { // Also this line is stupid enough for accessing files a lot and the data is large reader.Write(data[i]; } } retuen resData; } // For adding two MappableObjects public static MappableObject operator +(MappableObject A, Mappableobject B) { // Of course we have to make sure that all dimensions are correct. MappableObject result = new MappableObject(Path.GetTempFileName(), A.Blocks, A.BlockSize); for (int i = 0; i < Blocks; i++) { float[] dataA = A.GetBlock(i); float[] dataB = B.GetBlock(i); float[] C = new float[dataA.Length]; for (int j = 0; j < BlockSize; j++) { C[j] = A[j] + B[j]; } result.SetBlock(i, C); } } // For adding a single float to the whole data. public static MappableObject operator +(MappableObject A, float B) { // Of course we have to make sure that all dimensions are correct. MappableObject result = new MappableObject(Path.GetTempFileName(), A.Blocks, A.BlockSize); for (int i = 0; i < Blocks; i++) { float[] dataA = A.GetBlock(i); float[] C = new float[dataA.Length]; for (int j = 0; j < BlockSize; j++) { C[j] = A[j] + B; } result.SetBlock(i, C); } } // Of course this doesn't work, but maybe you can see the effect here. // when the += is automimplemented from the definition above I have to create another large // object which causes a loss of memory and also takes more time because of the operation -> altgough its // simple in the example, but in reality it's much more complex. public static MappableObject operator +=(MappableObject A, float B) { // Of course we have to make sure that all dimensions are correct. MappableObject result = new MappableObject(Path.GetTempFileName(), A.Blocks, A.BlockSize); for (int i = 0; i < Blocks; i++) { float[] dataA = A.GetBlock(i); for (int j = 0; j < BlockSize; j++) { A[j]+= + B; } result.SetBlock(i, A); } } } } 

你是否仍然认为+=是“自动实施”是好事。 如果您尝试在C#中进行高性能计算,您需要具备这些function以减less处理时间和内存消耗,如果有人有一个很好的解决scheme,非常感谢, 但不要告诉我,我必须使用静态方法,这只是一个解决方法 ,我没有看到为什么C#没有定义的情况下为了实现+= ,如果定义它将被使用。 有人说++=之间没有区别可以防止错误,但这不是我自己的问题吗?

我有完全相同的问题,我不可能回答这个人有更好的