結構變數作為方法的引數呼叫,在方法內部使用的“坑”你遇到過嗎?
阿新 • • 發佈:2022-04-29
很久沒有寫博了,今天一個同學在問結構變數的問題,問結構到底是傳遞值還是傳遞引用。查過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++;
}
這說明,定義一個結構變數,讓另外一個結構變數的值賦值給它,等於是複製這個結構變數的值。
往往有時候,我們為了敲程式碼方便,少寫幾個字,便定義一個臨時變數去引用原來的變數,而這種行為,對於操作結構變數,無疑是一個最大的坑,這個坑,你遇到過嗎?