flexage
flexage

Reputation: 457

C# Why are my list items being emptied when I clear the original object?

I basically have a list of Dictionaries like:

List<Dictionary<string, string>>

For the purposes of testing I'm fetching 36 dictionary items into the list and then returning the list at the end of my function.

The odd thing is when I populate the list, I can see the Key=>Value pairs of the dictionaries being added to the list in the Visual Studio Inspector, however upon clearing the original dictionary used to populate my list, all that remains is 36 empty items in the list.

Is there some weird List behaviour happening that I'm unaware of? A code snip is included below for reference...

    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;

Upvotes: 4

Views: 5692

Answers (5)

Steve
Steve

Reputation: 216273

You add the same INSTANCE of dictionary in the list for every loop.
It is only expected that when you clear the dictionary every one is emptied

to resolve the problem you need to add this to your cycle

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

However I need to ask you. Why to use a dictionary to store columns and rows? You could achieve your result with a DataTable

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

and forget the List and the Dictionary

Upvotes: 5

Servy
Servy

Reputation: 203811

As others have said, when you add the dictionary to the list you are only adding an additional reference to the same existing dictionary. That said, I'd suggest a different solution than copying it.

The problem is that your dictionary is at the top level of scope. It shouldn't be. You're trying to re-use the same dictionary over and over. You'll be better off simply defining the dictionary at a lower level, inside of the while loop:

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();
}
//...

Note the only change I made was moving the declaration of selectResult.

By creating a new dictionary for each iteration of the while loop you ensure that you're adding a new dictionary each time.

Upvotes: 0

Sam Harwell
Sam Harwell

Reputation: 99859

You are adding a reference to the Dictionary to your list, so changes in the original dictionary are also reflected in the instances you access through the list. If you want to add a copy of the Dictionary, you'll need to use something like this:

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

Upvotes: 0

Mike Zboray
Mike Zboray

Reputation: 40818

Dictionary is a reference type. You need to make a new one: selectResult = new Dictionary<string, string>() instead of calling Clear.

Upvotes: 0

radu florescu
radu florescu

Reputation: 4353

Because you did not clone it. And you copied the address of the first object. Use clone next time.

Deep cloning objects

Upvotes: 2

Related Questions