1. 程式人生 > 其它 >結構變數作為方法的引數呼叫,在方法內部使用的“坑”你遇到過嗎?

結構變數作為方法的引數呼叫,在方法內部使用的“坑”你遇到過嗎?

很久沒有寫博了,今天一個同學在問結構變數的問題,問結構到底是傳遞值還是傳遞引用。查過MSDN的都知道,結構預設是傳遞值的,因此在方法內部,結構的值會被複制一份。但是對於結構陣列,如果值還是要被複制一份,這個記憶體佔用是不是很多了呢? 一般來說,陣列引數傳遞的是引用,那麼陣列的元素呢?它是被複制的還是被引用的?如果結構陣列的元素象結構變數那樣也是複製的,那麼對於方法呼叫的記憶體佔用問題,就得好好考慮下了。

MSDN看了半天,也討論了半天,感覺還是沒有動手實驗最有說服力,我們先定義一個結構體:

struct Point
    {
        public int X;
        public int Y;
        public Point(int x, int y)
        {
            this.X = x;
            this.Y = y;
        }
    }

定義2個方法,分別以傳值和傳引用的方式來呼叫結構變數:

        static void TestStruc(Point p)
        {
            p.X++;
            p.Y++;

        }

        static void TestStruc2(ref Point p)
        {
            p.X++;
            p.Y++;

        }

呼叫程式碼:

            Point p = new Point(1, 2);
            TestStruc(p);
            Console.WriteLine("call by value Point X={0},Y={1}", p.X, p.Y);

            TestStruc2(ref p);
            Console.WriteLine("call by ref Point X={0},Y={1}", p.X, p.Y);

呼叫結果符合預期,以引用傳遞的結構變數,它的值被改變了:

Struct Pont(X,Y) Test:
call by value Point X=1,Y=2
call by ref Point X=2,Y=3

下面,試試結構陣列,看有何不同:

        static void TestStrucArray2(ref Point[] arr)
        {
            Point p = arr[0];
            p.X++;
            p.Y++;

        }

呼叫程式碼:

            Point[] arr = new Point[2];
            arr[0] = new Point(1, 2);
            arr[1] = new Point(3, 4);

            TestStrucArray(arr);
            Console.WriteLine("call by value Point[0]: X={0},Y={1}", arr[0].X, arr[0].Y);

結果:

call by value Point[0]: X=1,Y=2

方法內部對結果陣列元素的改變無效,難道結構陣列被複制了?

驚出一身冷汗!

改成引用引數的方式來試試,避免複製結構陣列:

       static void TestStrucArray2(ref Point[] arr)
        {
            Point p = arr[0];
            p.X++;
            p.Y++;

        }

結果:

call by value Point[0]: X=1,Y=2
call by ref Point[0]: X=1,Y=2

引用方式陣列還是被複制了?看來哪裡有問題阿。

去掉用一個結構變數來引用結構陣列的成員,直接操作結構陣列的元素,來看看呼叫結果:

        static void TestStrucArray3( Point[] arr)
        {
            //Point p = arr[0];
            arr[0].X++;
            arr[0].Y++;

        }

        static void TestStrucArray4(ref Point[] arr)
        {
            arr[0].X++;
            arr[0].Y++;

        }

呼叫程式碼:

            TestStrucArray4(ref arr);
            Console.WriteLine("call by ref Point[0] not use var : X={0},Y={1}", arr[0].X, arr[0].Y);
            arr[0].X = 1; arr[0].Y = 2;

            TestStrucArray3( arr);
            Console.WriteLine("call by var Point[0] not use var : X={0},Y={1}", arr[0].X, arr[0].Y);

結果:

call by ref Point[0] not use var : X=2,Y=3
call by var Point[0] not use var : X=2,Y=3

直接操作結構陣列的元素,元素的值被改變了,證明結構陣列沒有複製陣列元素的值,依然是對陣列的引用,上面的問題虛驚一場。

我們對比下前後不同的程式碼,發現TestStrucArray2 僅僅多了一行程式碼:

       static void TestStrucArray2(ref Point[] arr)
        {
            Point p = arr[0];
            p.X++;
            p.Y++;

        }

這說明,定義一個結構變數,讓另外一個結構變數的值賦值給它,等於是複製這個結構變數的值。

往往有時候,我們為了敲程式碼方便,少寫幾個字,便定義一個臨時變數去引用原來的變數,而這種行為,對於操作結構變數,無疑是一個最大的坑,這個坑,你遇到過嗎?