※ 引述《jamod (jasper)》之銘言:
: 應該是有關記憶體的問題,但上網找了一些說明,還是不是很了解
: =============================================
: public struct s_Test{
: public int i;
: }
: 上面是我自訂的一個struct
: =======================================================
: s_Test t = new s_Test();
: List<s_Test> list = new List<s_Test>();
: list.Add(t);
: list[0].i = 10;
: 當我用上面的方法修改list[0].i的值會出錯,
因為 list[0] 實際上是呼叫 List class 的 indexer get method
它是個 function call 會回傳整個 struct 的複本 (因為 C# 無法回傳 ref)
當你對複本修改內容,對原本存在 List 中的 struct 毫無效果
既然無效果,compiler 乾脆把它擋下來,避免 programmer 誤會它有效
: 看說明是叫我new一個新的struct直接覆蓋list[0]
: 所以我改成:
: ===========================================================
: List<s_Test> list = new List<s_Test>();
: list.Add(t);
: s_Test temp = new s_Test();
: temp.i = 10;
: list[0] = temp;
: 上面這樣才可以變更裡面的值,但是我改成陣列來儲存:
這邊之所以可以直接變更值,是因為它呼叫到 List class 的 indexer set method
它也是個 function call,會把 temp 整個當參數傳進去,把原本的 struct 蓋掉
所以當你只想修改 struct 中的單一欄位時
必需要寫三行
s_Test temp = list[0];
temp.i = 10;
list[0] = temp;
這是 C# 語言本身的限制
: ===========================================================
: s_Test[] array = new s_Test[10];
: array[0] = t;
: array[0].i = 10;
: 就可以直接修改i了,想請問有沒有高手能夠解釋原因?
: 非常感謝!
至於 array 就不是一個 class,而是語言本身提供的功能
使用 indexer 取值與 function call 無關
對 array[i] 做的操作完全對應到 array 中的 struct
就像你直接使用那個 struct 一樣
因此直接用 array[0].i 也沒問題
如果你研究過 C++ 的 l-value / r-value / reference
再看到這個現象會比較容易理解
C# 稍微犧牲了一點彈性
但加強了記憶體的安全 (不會有 dangling reference)