人, 我在下一段代码中得到了编译错误('无法修改字典的返回值,因为它不是变量'):
public class BaseForm : Form
{
protected void StoreGridViewPosition(DataGridView grid)
{
if (grids.ContainsKey(grid))
{
grids[grid].RowIndex = grid.CurrentCell.RowIndex;
grids[grid].ColumnIndex = grid.CurrentCell.ColumnIndex;
}
Cell s = new Cell();
s.RowIndex = 213;
}
protected void LoadGridViewPosition(DataGridView grid)
{
}
private Dictionary<DataGridView, Cell> grids = new Dictionary<DataGridView, Cell>();
private struct Cell
{
public int RowIndex;
public int ColumnIndex;
}
}
但如果我用类替换struct(Cell),那么它可以正常工作。 为什么会这样?
答案 0 :(得分:6)
这不会像您期望的那样有效。当你打电话:
grids[grid].
结构的副本是从索引器返回的,而不是引用。所以当你进入它时:
grids[grid].RowIndex = grid.CurrentCell.RowIndex;
您实际上是在设置结构的副本。然后立即丢弃该副本。所有这些行为都源于结构的值类型语义。
如果您使用结构,您可以执行的操作是将全新结构设置到单元格中:
grids[grid] = new Cell { RowIndex = 3, ColumnIndex = 1 };
或者拉一张旧版本并将其重新设置(暂时忽略结构应该总是不可变 :-):
var cell = grids[grid];
cell.RowIndex = 3;
grids[grid] = cell;
将定义更改为类意味着索引器会向该类返回引用,您可以将其变异,因为引用和字典的引用都指向同一个基础对象。
编译器说(不是很多的话)你无意中试图改变你认为你正在改变的副本。 如果将struct作为类的属性公开并尝试改变struct成员,则可以轻松犯同样的错误:
<击> myClass.MyPointStruct.X = 2;
击>
(这似乎至少在新编译器中给出了相同的错误信息,我可以在一段时间内宣誓它曾经让你这样做......)
或者如果将结构转换为接口,则装箱副本。
这个问题非常相似:
答案 1 :(得分:1)
当你的StoreGridViewPosition调用你的Cell时,你会得到一个struct的副本。您的呼叫会更新该值,然后将其丢弃(即没有任何用处)。
答案 2 :(得分:0)
构造一个值类型,所以当你来自你的字典时,你得到的是一个站在字典中的副本。 C#实际上阻止你做坏事 惊讶...