2012-09-19 131 views
4

我有一个需要存储在集合中的结构。该结构具有返回字典的属性。从另一个集合中访问结构集合属性

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

当测试时我发现如果我将项目添加到集合,然后尝试访问字典,结构值属性永远不会更新。

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 

但是,如果我先加载项目,然后将其添加到集合值字段保持。

var collection = new ItemCollection(); 
var item = new Item(); 
item.Values.Add("myKey", "myValue"); 
collection.Add(item); 
Trace.WriteLine(collection[0].Values["myKey"]); // ok 

我已经决定,一个结构是这种类型的错误的选项,并使用一个类时,不会出现问题,但我很好奇什么是两种方法之间的不同。任何人都可以解释发生了什么?

+1

msdn doc:这是一个msdn示例http://msdn.microsoft.com/en-us/library/vstudio/8b0bdca4.aspx – Cybermaxs

回答

1

正如之前提到的,将struct Item更改为class Item。当您使用struct时,表达式collection[0]不会返回对new ItemCollection { new Item() }中创建的对象的引用,而是会创建它的副本并将其提供给您。

+0

你可以在这个节目上展示吗? –

2

更改你的结构是一个类,而不是:

public class Item {} 

现在我不是那熟悉的内脏,但结构是值类型,一类是引用类型,而且我相信,有在那里是逻辑,这解释了为什么在运行第一个代码示例时出现异常。

我希望有人能够给你一个更彻底的答案,但现在,只需将结构更改为一个类。

+0

正如你可以在这里看到的(http://stackoverflow.com/questions/521298/when-to-use-struct-in-c),我认为有一个这种情况的结构并不理想。 – Cybermaxs

1

“Item”是一个值项。这意味着,如果您访问该集合,则会创建一个副本。所有的操作都在该副本

collection[0].Values.Add("myKey", "myValue"); 

这里一份拷贝,则该值get访问的第一个项目的完成创建一个新的实例,该实例存储在副本,然后加入该项目。那么副本被销毁。

一个解决方法是建立在价值观上的结构

public struct Item 
{ 
    private IDictionary<string, string> values = new Dictionary<string, string>(); 
    public IDictionary<string, string> Values 
    { 
     get 
     { 
      return this.values; 
     } 
    } 
} 

的创建字典直接,如果你访问集合,一个副本。但此副本包含对原始值相同值字典的引用。所以原始字典被修改

+0

谢谢。你看起来似乎是正确的,但是编译器不会允许赋值到values字段 - “结构中不能有实例字段初始值设定项” – paddyb

+0

结构可以有一个构造函数。 –

+0

@Baboon是真的,但它仍然不能分配到值域 – paddyb

相关问题