Reputation: 77
I have a struct that I need to store in a collection. The struct has a property that returns a Dictionary.
public struct Item
{
private IDictionary<string, string> values;
public IDictionary<string, string> Values
{
get
{
return this.values ?? (this.values = new Dictionary<string, string>());
}
}
}
public class ItemCollection : Collection<Item> {}
When testing I've found that if I add the item to the collection and then try to access the dictionary the structs values property is never updated.
var collection = new ItemCollection { new Item() }; // pre-loaded with an item
collection[0].Values.Add("myKey", "myValue");
Trace.WriteLine(collection[0].Values["myKey"]); // KeyNotFoundException here
However if I load up the item first and then add it to a collection the values field is maintained.
var collection = new ItemCollection();
var item = new Item();
item.Values.Add("myKey", "myValue");
collection.Add(item);
Trace.WriteLine(collection[0].Values["myKey"]); // ok
I've already decided that a struct is the wrong option for this type, and when using a class the issue doesn't occur, but I'm curious what's different between the two methods. Can anybody explain what's happening?
Upvotes: 4
Views: 135
Reputation: 166
As it was mentioned before, change struct Item
to class Item
. When you use struct
, an expression collection[0]
returns not a reference to object created in new ItemCollection { new Item() }
but rather creates a copy of it and gives it to you.
Upvotes: 1
Reputation: 9417
"Item" is a value item. that means, if you access the collection, a copy is made. all operations are done on that copy
collection[0].Values.Add("myKey", "myValue");
here of the first item a copy is made, then the Value get accessor creates a new instance, which is stored in the copy, and then the item is added. then the copy is destroyed.
a workaround would be creating the Values dictionary direct on the creating of the struct
public struct Item
{
private IDictionary<string, string> values = new Dictionary<string, string>();
public IDictionary<string, string> Values
{
get
{
return this.values;
}
}
}
if you access the collection, a copy is made. but this copy contains a reference to the same values dictionary like the original one. so the original dictionary is modified
Upvotes: 1
Reputation: 29186
Change your struct to be a class instead:
public class Item {}
Now I'm not that familiar with the innards, but a struct is a value type and a class is reference type, and I believe that there is logic in there which explains why you get an exception when running the first code example.
I'm hoping someone can step in an give you a more thorough answer, but for now, just change the struct to a class.
Upvotes: 2