为字典中的struct赋值时的编译错误

Dzm*_*try 1 c# struct class winforms

大家好,我在下一段代码中得到了编译错误('不能修改字典的返回值,因为它不是变量'):

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我用类替换struct(Cell),那么它可以正常工作.为什么会这样?

Ada*_*rth 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;
Run Code Online (Sandbox Code Playgroud)

将定义更改为类意味着索引器返回对该类的引用,您可以在引用和字典引用指向同一基础对象时进行变异.

编译器说(不是很多的话)你无意中试图改变你认为你正在改变的副本. 如果将struct作为类的属性公开并尝试改变struct成员,则可以轻松地犯同样的错误:

myClass.MyPointStruct.X = 2;

(这似乎至少在新的编译器中给出了相同的错误信息,我可以在某一时刻宣誓它曾经让你这样做......)

或者,如果将结构转换为接口,则装箱副本.

这个问题非常相似:

在Dictionary中修改Struct变量