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

时间:2011-09-16 11:53:52

标签: c# winforms class struct

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

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),那么它可以正常工作。 为什么会这样?

3 个答案:

答案 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;

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

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

这个问题非常相似:

Modify Struct variable in a Dictionary

答案 1 :(得分:1)

当你的StoreGridViewPosition调用你的Cell时,你会得到一个struct的副本。您的呼叫会更新该值,然后将其丢弃(即没有任何用处)。

答案 2 :(得分:0)

构造一个值类型,所以当你来自你的字典时,你得到的是一个站在字典中的副本。 C#实际上阻止你做坏事  惊讶...