应该只 return 临时对象更改原始对象的重载增量运算符。为什么?

Overloaded increment operator that's supposed to only return a temp object changes the original object. Why?

我目前正在学习 C# 课程(有点太过时且术语太多,无法启动),其中一个演示应该教我们如何在 class 中重载运算符。他们创建一个数组 class 并重载一元运算符 - 和 ++。它们的编写方式相同,创建一个临时新数组对象,其中每个整数都被反转或递增,然后 return 临时。但是,正如打印数组所揭示的那样,- 操作不会更改原始数组,而 ++ 会。为什么?该课程在这方面没有解释任何内容,甚至没有说明所需的输出是什么。我什至不知道它是否应该以这种方式工作,或者自本课程写作的过时时间以来发生了一些变化。

class DemoArray
    {
        int[] MyArray;
        public DemoArray(int size)
        {
            MyArray = new int[size];
        }
        public DemoArray(params int[] arr)
        {
            MyArray = new int[arr.Length];
            for (int i = 0; i < MyArray.Length; i++) MyArray[i] = arr[i];
        }
        public int LengthArray
        {
            get { return MyArray.Length; }
        }
        public int this[int i]
        {
            get
            {
                if (i < 0 || i >= MyArray.Length)
                    throw new Exception("out of array bounds");
                return MyArray[i];
            }
            set
            {
                if (i < 0 || i >= MyArray.Length)
                    throw new Exception("out of array bounds");
                else MyArray[i] = value;
            }
        }

        public static DemoArray operator -(DemoArray x)
        {
            DemoArray temp = new DemoArray(x.LengthArray);
            for (int i = 0; i < x.LengthArray; ++i)
                temp[i] = -x[i];
            return temp;
        }
        public static DemoArray operator ++(DemoArray x)
        {
            DemoArray temp = new DemoArray(x.LengthArray);
            for (int i = 0; i < x.LengthArray; ++i)
                temp[i] = x[i] + 1;
            return temp;
        }
        public void Print(string name)
        {
            Console.WriteLine(name + ": ");
            for (int i = 0; i < MyArray.Length; i++)
                Console.Write(MyArray[i] + " ");
            Console.WriteLine();
        }
}
    class Program
    {
        static void Main()
        {
            try
            {
                DemoArray Mas = new DemoArray(1, -4, 3, -5, 0);
                Mas.Print("Original array");
                Console.WriteLine("\nUnary inversion");
                DemoArray newMas = -Mas;
                Mas.Print("Array Mas");
                newMas.Print("Array newMas");
                Console.WriteLine("\nPrefix increment");
                DemoArray Mas1 = ++Mas;
                Mas.Print("Array Mas");
                Mas1.Print("Array Mas1=++Mas");
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }
    }

并且输出显示:

Original array:
1 -4 3 -5 0

Unary inversion
Array Mas:
1 -4 3 -5 0
Array newMas:
-1 4 -3 5 0

Prefix increment
Array Mas:
2 -3 4 -4 1
Array Mas1=++Mas:
2 -3 4 -4 1

那么,为什么原来的数组Mas又被重载的增量修改了呢?顺便说一句,我已经尝试过重载 ++ 运算符 来反转 整数和 - 运算符 来增加 它们,而 - 运算符仍然没有更改原始数组,而 ++ 运算符。

C#通过调用重载运算符函数并对结果进行赋值,自动构造递增、递减和复合赋值运算符。

您可以阅读 C# 语言规范中的规则 section 11.7.14 Postfix increment and decrement operators

特别是,您在定义 operator+ 时免费获得 +=,并且在定义 operator++ 时同时获得前缀增量和后缀增量,这是有效的,因为 C# 控制何时分配发生(因此它可以为前缀和后缀选择不同的顺序)。

section 14.10.2 Unary operators

中甚至还有一个注释

Unlike in C++, this method should not modify the value of its operand directly as this would violate the standard semantics of the postfix increment operator.

(C++要求程序员为prefix-increment和postfix-increment提供单独的函数)


综上所述,您认为 ++Mas 更改了原始数组的结论是不正确的。原始数组仍然在那里,没有变化(直到垃圾收集器找到它)。但是变量 Mas 指向新数组,与 Mas1 相同。

试试这个片段来证明:

DemoArray Mas = new DemoArray(1, -4, 3, -5, 0);
DemoArray Old = Mas;
DemoArray Mas1 = ++Mas;
Mas.Print("Array Mas");
Mas1.Print("Array Mas1=++Mas");
Old.Print("Array Old");
Console.WriteLine(ReferenceEquals(Mas, Old)); // false
Console.WriteLine(ReferenceEquals(Mas, Mas1)); // true