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 += y
和x = x + y
行为不完全相同的情况下,允许您单独覆盖它可能会产生问题。
在较低的级别上,C#编译器很可能会将这两个expression式编译为相同的字节码,这意味着运行时很可能在程序执行期间不能以不同的方式对待它们。
我可以理解,你可能想把它当作一个单独的操作来处理:在像x += 10
这样的语句中,你知道你可以改变x
对象的位置,也许会节省一些时间/内存,而不是创build一个新的对象x + 10
之前分配在旧的参考。
但是考虑这个代码:
a = ... b = a; a += 10;
应该在最后? 对于大多数types,不, a
比b
多10。 但是,如果你可以重载+=
运算符来适应变化,那么是的。 现在认为a
和b
可以传递到程序的很远的部分。 如果您的对象开始更改代码所不期望的位置,则可能的优化可能会产生令人困惑的错误。
换句话说,如果性能非常重要,用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#没有定义的情况下为了实现+=
,如果定义它将被使用。 有人说+
和+=
之间没有区别可以防止错误,但这不是我自己的问题吗?
我有完全相同的问题,我不可能回答这个人有更好的