※ 引述《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)