3

基本的に、次のような辞書のリストがあります。

List<Dictionary<string, string>>

テストの目的で、36 個の辞書項目をリストにフェッチし、関数の最後でリストを返します。

奇妙なことに、リストにデータを入力すると、辞書の Key=>Value ペアが Visual Studio Inspector のリストに追加されていることがわかりますが、リストにデータを入力するために使用された元の辞書をクリアすると、36 しか残っていません。リスト内の空のアイテム。

私が気付いていないリストの奇妙な動作はありますか? 参照用にコードスニップを以下に示します...

    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

5 に答える 5

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

リストと辞書を忘れて

于 2013-03-22T15:52:39.523 に答える
2

クローンを作成しなかったからです。そして、最初のオブジェクトのアドレスをコピーしました。次回はクローンを使用します。

ディープクローンオブジェクト

于 2013-03-22T15:51:58.793 に答える
0

Dictionaryは参照型です。selectResult = new Dictionary<string, string>()を呼び出す代わりに、新しいものを作成する必要がありますClear

于 2013-03-22T15:52:44.427 に答える
0

リストにへの参照を追加しているDictionaryため、元のディクショナリの変更は、リストからアクセスするインスタンスにも反映されます。のコピーを追加する場合はDictionary、次のようなものを使用する必要があります。

allResults.Add(new Dictionary<string, string>(selectResult));
于 2013-03-22T15:53:51.097 に答える
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ループの反復ごとに新しいディクショナリを作成することで、毎回新しいディクショナリを追加していることを確認できます。

于 2013-03-22T15:59:38.697 に答える