假設瓷磚在構造函數中初始化,並且Tile是一個結構。兩者之間有什麼明顯的區別?
CASE 1
// Case 1: ref T indexer
class Map {
Tile[,] tiles;
public ref Tile this[int x, int y]
=> ref tiles[x, y];
}
您在返回ref
到索引Title
對象,所以你可以修改它,甚至將其設置爲不同的對象。這是C#7.0的一個新特性(就像你已經標記的那樣),其中它允許返回一個ref
,然後你可以存儲它。換句話說,它返回的存儲位置不是值。
由於您正在返回存儲位置,因此可以將新的Tile
對象完全分配給索引項目。沒有ref
,你只能修改它。
CASE 2
class Map {
Tile[,] tiles;
public Tile this[int x, int y] {
get => tiles[x, y];
set => tiles[x, y] = value;
}
}
這裏是相同的,但沒有C#7.0的簡潔:
class Case2MapWithoutCSharp7
{
Tile[,] tiles;
public Tile this[int x, int y]
{
get { return tiles[x, y]; }
set { tiles[x, y] = value; }
}
}
由於Tile
是struct
,當你索引它,你會得到一個副本,如果你試試這個(假設Tile
有一個屬性X
):
map[0, 0].X = 10;
錯誤CS1612無法修改'Case2MapWithoutCSharp7.this [int,int]'的返回值,因爲它不是變量。
編譯器拋出該錯誤以清楚地明確你認爲自己在做什麼(修改索引項),這實際上並不是你正在做的。您實際上正在修改副本,以便強制您執行此操作。所以,爲了能夠設置X
,你需要做的是這樣的副本:
var tile = map[0, 0];
tile.X = 10;
你可以閱讀更多關於該錯誤here。
如果瓷磚是class
怎麼辦?
在第一種情況下,由於您要返回存儲位置,因此您可以完全將新的Tile
對象分配給索引項。
在第二種情況下,如果沒有ref
,因爲class
對象是通過引用傳遞的,所以您將能夠修改它,但不能將引用設置爲整個新對象。所以,你可以這樣做:
map[0, 0].X = 2;
但是,如果你這樣做:
var tile = map[0, 0];
tile = new Tile();
tile.X = 5;
顯然你是變異了一個全新Tile
,而不是一個你索引。
只有當類型可變時纔有區別 –
是的,差別很大。給平鋪一個X屬性並嘗試地圖[0,0] .X = 42; –
哦,我明白了。情況2將不允許您修改其屬性。謝謝,我會和前者一起去。 :) – Dave