none
Dictionary clone with values as list of objects RRS feed

  • Question

  • how can I clone a dictionary of type

    Dictionary>string,List<SomeClass>)

    where the SomeClass don't have reference to the original object?

    also when I tried to loop in run time, I get some times on the foreach loop

    error the Dictionary has changed - how can I avoid this?

    Sunday, August 4, 2019 7:36 AM

All replies

  • Hello,

    For clarity please show your current code. In regards to "the dictionary has changed" sounds like you are using a for/each, try using a standard for.


    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    Sunday, August 4, 2019 11:47 AM
    Moderator
  • The second question is easier to answer. A rule for the foreach loop is that while you are looping you cannot modify the same collection on which you are looping. So if you do a foreach over a List (for instance), you cannot add or remove items from the list while the loop is running. If you need to do this, you have to use a different kind of loop instead of a foreach.

    Now, about the "clone", we need to make a distinction between a shallow clone and a deep clone. A shallow clone just clones the first level of items, but does not descend into each item to clone its contents. Therefore, the "first level" clone contains a reference to the same item in each collection. In the case of the Dictionary one easy way to clone it is to use an overload of the constructor that takes a Dictionary as an argument. This will create a new dictionary with the same members as the one that you pass as an argument.

    This new Dictionary will have the same members as your first dictionary. But each of the two copies will contain references to the same instance of each SomeClass. If you need a deep clone, meaning that you need to clone each of the SomeClass in the dictionary, there is no universal way of doing this. It is specific to each class. There is a standard way to do this, which is to implement the interface ICloneable within your class. But this is a manual task that has to be done expressly for each class that you need to clone in this way.

    Sunday, August 4, 2019 11:55 AM
    Moderator
  • Hi,

    about the foreach loop, if I will use regular loop over Dictionary

    (which is being changed in another method) I can face same issue.

    what's the safest way to loop a dictionary?

    Sunday, August 4, 2019 1:45 PM
  • Hi want 2 Learn,

    Thank you for posting here.

    For your question, you want to clone dictionary.

    I write a simple code, you could have a look.

     class Program
        {
            static void Main(string[] args)
            {
                Dictionary<string, List<Example>> keys = new Dictionary<string, List<Example>>();
                List<Example> list = new List<Example>();
                list.Add(new Example { Age = 10, Name = "Test1" });
                list.Add(new Example { Age = 11, Name = "Test2" });
                keys.Add("example1", list);
                keys.Add("example2", list);
                var dic = new Dictionary<string, List<Example>>(keys); // cloned dictionary
    
            }
        }
        public class Example
        {
            public int Age { get; set; }
            public string Name { get; set; }
    
        }

    Best Regards,

    Jack


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Monday, August 5, 2019 5:51 AM
    Moderator
  • In some cases, you can use ToArray to solve the “System.InvalidOperationException: 'Collection was modified; enumeration operation may not execute'” error.

    For example, the next example tries removing the keys that start with “a”;

       foreach( var k in myDictionary.Keys )

       {

          if( k.StartsWith( "a" ) ) myDictionary.Remove( k ); // ERROR

     

       }

     

    To avoid the errors, try this:

       foreach( var k in myDictionary.Keys.ToArray( ) )

       {

          if( k.StartsWith( "a" ) ) myDictionary.Remove( k );

       }

     

    Show details about your specific loops.

    Monday, August 5, 2019 6:50 AM
  • Hi @Jack

    I checked your example it's not clonse.

    for example I did :

    ((List<Example>) dic["example1"])[0].Age = 999;

    and when I checked the keys dictionary :

    ((List<Example>) keys["example1"])[0]

    the value has changed to 999 as well....

    Monday, August 5, 2019 8:10 AM
  • Hi @Viorel

    I just want to loop over the dictionary

    while other methods can change the dictionary (add/remove keys)

    and looked for the way to avoid errors

    Monday, August 5, 2019 8:12 AM
  • for example I did :

    ((List<Example>) dic["example1"])[0].Age = 999;

    and when I checked the keys dictionary :

    ((List<Example>) keys["example1"])[0]

    the value has changed to 999 as well....

    EXACTLY! That's precisely what I was telling you in my previous response, when I told you to distinguish between a shallow clone and a deep clone. The code you are referring to was making a shallow clone, but apparently you were expecting a deep clone.

    There is no perfect and universal way to make a deep clone. You need to code it case-by-case. In the simplest case were the class only contains value types or immutable types, you can use object.MemberwiseClone to clone each of the objects. But this may or may not work, depending on the internal structure of your class. As I said, you need to carefully consider each of your classes to decide how to clone it; there is no universal solution that will work every time.

    Monday, August 5, 2019 10:51 AM
    Moderator
  • I just want to loop over the dictionary

    while other methods can change the dictionary (add/remove keys)

    and looked for the way to avoid errors

    The solution that they gave you in a previous answer using .ToList() makes a copy of your dictionary. Then you can loop over this copy, and in the middle of the loop you can add/remove members from the original dictionary. Since this doesn't affect the copy on which you are looping, the loop can continue and you avoid the errors.

    Monday, August 5, 2019 10:54 AM
    Moderator
  • I would just like to mention that, generally speaking, you are not supposed to loop through a dictionary at all. The whole purpose of a dictionary is that you can perform lookup via a key, so there's no need to loop.

    Think of a real-life dictionary, made out of paper. If I want to know the definition of a word, say 'scarab', I don't have to first read the definition for 'a', then 'aardvark', and so on through every word in order until I get to the one I'm looking for. Instead, I can use my knowledge of the alphabet to go (more or less) straight to the definition I want (the word is the 'key', the definition is the 'value').

    Many programmers make the mistake of using a dictionary like a list when they are dealing with pairs of values, but that approach is just plain wrong. If you want to loop through a list, then you should use a List (or an array). Only use a dictionary when you need to do lookup via the key, as per its intended purpose.

    Tuesday, August 6, 2019 12:06 AM