Dzmitry
Dzmitry

Reputation: 749

Compilation error when assign value to struct in dictionary

folks, I've get compilation error('Can not modify the return value of dictionary because it's not a variable') in next code :

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;
    }
}

But if i'll replace struct(Cell) with class, then it works fine. Why it happens ?

Upvotes: 1

Views: 297

Answers (3)

Adam Houldsworth
Adam Houldsworth

Reputation: 64477

This won't work as you expect. When you call:

grids[grid].

A copy of the struct is returned from the indexer, not a reference. So when you set into it:

grids[grid].RowIndex = grid.CurrentCell.RowIndex;

You are actually setting into a copy of the struct. This copy is then immediately discarded. All of this behaviour stems from the value type semantics of structs.

All you can do if you use a struct is set a brand new struct into the cell:

grids[grid] = new Cell { RowIndex = 3, ColumnIndex = 1 };

Or pull a copy of the old one and set it back in (ignoring for a moment that structs should really always be made immutable :-) :

var cell = grids[grid];
cell.RowIndex = 3;
grids[grid] = cell;

Changing the definition to a class means the indexer returns a reference to that class, which you can mutate as both your reference and the dictionary's reference are pointing at the same underlying object.

The compiler is saying (in not so many words) that you are inadvertently trying to change a copy of what you think you are changing. You can make the same mistake easily if you expose a struct as a property of a class and try to mutate struct members thus:

myClass.MyPointStruct.X = 2;

(This appears to give the same error message in the new compiler at least, I could have sworn at one point it used to let you do this...)

Or if you cast the struct to an interface, boxing boxes a copy.

This question is very similar:

Modify Struct variable in a Dictionary

Upvotes: 6

AndrewC
AndrewC

Reputation: 6730

When your StoreGridViewPosition calls your Cell, you get a copy of the struct inside. Your call updates the value, and then throws it away (i.e. nothing useful).

Upvotes: 1

VdesmedT
VdesmedT

Reputation: 9113

struct a value types so when coming from your dictionary, what you get is a copy of the one standing in the dictionary. C# is actually preventing you from having bad surprise...

Upvotes: 0

Related Questions