Skip to content

C# 奇怪的值类型方法调用

🏷️ C#

创建一个 Point 类型,拥有 xy 两个私有变量,一个 Change 方法改变 xy 的值,一个重写的 ToString 方法.

csharp
using System;

namespace StructSample
{
    class Program
    {
        static void Main(string args)
        {
            Point p1 = new Point(1, 1);
            Console.WriteLine(p1); // ( 1, 1 )

            p1.Change(2, 2);
            Console.WriteLine(p1); // ( 2, 2 )

            Object o = p1;
            Console.WriteLine(o); // ( 2, 2 )

            ((Point)o).Change(3, 3);
            Console.WriteLine(o); // ( 2, 2 )

            Console.ReadLine();
        }
    }

    struct Point
    {
        private int m_x, m_y;

        public Point(int x, int y)
        {
            m_x = x;
            m_y = y;
        }

        public void Change(int x, int y)
        {
            m_x = x;
            m_y = y;
        }

        public override string ToString()
        {
            return String.Format("( {0}, {1} )", m_x, m_y);
        }
    }
}

前面 3 次的输出都很正常,第四次输出跟预想的就不一样了,虽然调用了 Change(3, 3),但输出仍为 ( 2, 2 )

原因还在于值类型的装箱和拆箱。看一下第二次调用 Change 的代码:

csharp
((Point)o).Change(3, 3);

因为 Object 类型没有 Change 方法,所以 o 必须显示转换为 Point 型才能调用 Change 方法。

这里会发生一次拆箱,将 o 拆箱后放入栈中,然后调用 Change 方法改变栈中的值,执行结束后栈中的值变为 ( 3, 3)

Change 方法结束后,栈中的值并不会再次装箱,而且该值也不会再被引用到,会立即被系统回收。

堆中 o 变量引用的值由于没有发生变更,所以打印的结果仍然为 ( 2, 2)