2013-03-22 40 views
3

我基本上有一个像字典的名单:C#为什么清理原始对象时我的清单项目被清空?

List<Dictionary<string, string>> 

对于我取36字典项到列表中,然后在我的函数的端返回的列表中的测试目的。

奇怪的是,当我填充列表时,我可以看到在Visual Studio Inspector中添加到列表中的字典的Key => Value对,但是在清除用于填充我的列表的原始字典时,所有仍然是列表中的36个空项目。

有没有我不知道的一些奇怪的List行为发生?以下代码片段供参考...

List<Dictionary<string, string>> allResults = new List<Dictionary<string, string>>(); 
    Dictionary<string, string> selectResult = new Dictionary<string, string>(); 

    MySqlCommand cmd = new MySqlCommand(query, conn); 
    MySqlDataReader dataReader = cmd.ExecuteReader(); 

    try 
    { 
     while (dataReader.Read()) 
     { 
      for (int i = 0; i < dataReader.FieldCount; i++) 
      { 
       selectResult.Add(dataReader.GetName(i).ToString(), dataReader.GetValue(i).ToString()); 
      } 
      allResults.Add(selectResult); 

      //Something to do with this next line seems to cause the List to also lose the values stored in the Dictionary, is clearing the dictionary not allowed at this point and the list is simply referencing the Dictionary rather than 'making a copy'? 
      selectResult.Clear(); 
     } 
     dataReader.Close(); 
    } 

    catch { } 

    this.Close(); 

    return allResults; 

回答

4

你加字典的同一个实例列表中的每一个循环。
这只是预期,当你清除字典的每一个被清空

解决您需要这可是我要问你添加到您的周期

while (dataReader.Read()) 
    { 
     // at every loop, create a new instance of dictionary using the same variable 
     Dictionary<string,string> selectResult = new Dictionary<string, string>(); 
     for (int i = 0; i < dataReader.FieldCount; i++) 
     { 
      selectResult.Add(dataReader.GetName(i).ToString(), dataReader.GetValue(i).ToString()); 
     } 
     // Adding a different copy of the dictionary in the list 
     allResults.Add(selectResult); 
    } 

问题。为什么要使用字典来存储列和行? 你可以用一个DataTable

DataTable dt = new DataTable(); 
    dt.Load(dataReader); 

实现你的结果,忘记了列表和字典

+0

真的没有什么好的理由在'while'循环之外定义字典。它只意味着你可能会忘记重新初始化它,或者在循环的范围之前/之后使用它,它只是没有意义被使用。如果你在循环中定义它,你确保它每次都被编译器初始化,并确保它不能用在其它没有意义的上下文中。 – Servy 2013-03-22 16:00:59

+0

是的,我同意并修复答案,但是我仍然对这种数据表的改造感到困惑。 – Steve 2013-03-22 16:03:12

+0

噢,现在我的答案和你的答案是一样的...... – Steve 2013-03-22 16:05:32

2

因为您没有克隆它。并且您复制了第一个对象的地址。 下一次使用克隆。

Deep cloning objects

0

Dictionary是引用类型。您需要创建一个新的:selectResult = new Dictionary<string, string>()而不是调用Clear

0

您正在为列表添加对Dictionary的引用,以便原始字典中的更改也反映在您通过列表访问的实例中。如果您要添加的Dictionary副本,你需要使用这样的事情:

allResults.Add(new Dictionary<string, string>(selectResult)); 
0

正如其他人所说,你添加字典时到列表中只添加额外的参考到相同的现有字典。这就是说,我会建议一个不同的解决方案,而不是复制它。

问题是您的字典处于作用域的顶层。它不应该。你试图一遍又一遍地重复使用相同的字典。你会更好简单地定义字典在一个较低的水平,while循环内:

List<Dictionary<string, string>> allResults = new List<Dictionary<string, string>>(); 

MySqlCommand cmd = new MySqlCommand(query, conn); 
MySqlDataReader dataReader = cmd.ExecuteReader(); 

try 
{ 
    while (dataReader.Read()) 
    { 
     Dictionary<string, string> selectResult = new Dictionary<string, string>(); 
     for (int i = 0; i < dataReader.FieldCount; i++) 
     { 
      selectResult.Add(dataReader.GetName(i).ToString(), dataReader.GetValue(i).ToString()); 
     } 
     allResults.Add(selectResult); 
    } 
    dataReader.Close(); 
} 
//... 

注意我所做的唯一的变化是移动selectResult声明。

通过为while循环的每次迭代创建一个新字典,确保您每次都添加一个新的字典。