Click here to Skip to main content
15,119,410 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hello,

I have a Dictionary with Dictionary<int,string> dict_1 and another as a backup with same type dict_2. Any changes in dict_1 must NOT reflect in dict_2. when user wants to revert the original dictionary, dict_2 must copied to dict_1. Please help me on this.

What I have tried:

Tried the below code but couldn't work,
C#
Dictionary<int,string> dict_1 =new Dictionary<int, string="">();
dict_1.Add(1,"a");
dict_1.Add(1,"b");
dict_1.Add(1,"c");
Dictionary<int, string=""> dict_2 =new Dictionary<int,string>(dict_1);
dict_1.Remove(1);//affects dict_2 also which should not happen.
Posted
Updated 17-May-19 22:29pm
v2
Comments
Richard Deeming 17-May-19 8:10am
   
Your sample code won't work, since you've added the same key to dict_1 three times.

Correcting that, your sample code doesn't behave as you've described. Removing an item from dict_1 doesn't remove it from dict_2.

Update your question to show the actual code you're using.
phil.o 17-May-19 8:15am
   
The code you provided would not even compile, due to the string="" in dict_2 declaration; but I assumme this is just a typo when you wrote your question.
But there is another serious issue: you are trying to add to a dictionary a record whose key already exists; the third line of the code you show will throw an ArgumentException because you are trying to add an existing key to the dictionary.
Finally, using the constructor like you did should not lead to an instance equality between dist_1 and dist_2. According to Dictionary<TKey,TValue>(IDictionary<TKey,TValue>)[^], elements from dict_1 will be copied to dict_2.
All of this makes me think that the code you showed is not exactly the code that you have. Please make sure we have your actual code.

First step is to fix your code so it compiles.

Second step is to fix the code so it runs.

The third step is to debug it and observe what is going on.

You will for example end up with something like this (using Console.WriteLine, of course you would use a debugger)
using System;
using System.Collections.Generic;
					
public class Program
{
    public static void Main()
    {
        Dictionary<int,string> dict_1 =new Dictionary<int, string>();
        dict_1.Add(1,"a");
        dict_1.Add(2,"b");
        dict_1.Add(3,"c");
        Dictionary<int, string> dict_2 =new Dictionary<int,string>(dict_1);
        dict_1.Remove(1);//affects dict_2 also which should not happen. 
        Console.WriteLine(dict_1.Count);
        Console.WriteLine(dict_2.Count);
    }
}


You can run it here:
C# Online Compiler | .NET Fiddle[^]

As expected, outputs 2 followed by 3, so clearly the content of the dictionaries differs. The debugger will allow you to observe the precise content of the dictionary.
   
v2
Comments
Maciej Los 17-May-19 16:06pm
   
5ed!
I recently posted an example of merging two Dictionaries where, in the case of duplicate Values, you can control which Value is used in the merged (new) Dictionary [^]

In order for dict2 to be truly independent of dict1, you must do a deep copy of the KeyValuePairs, however, if the Keys are integers, and the Values strings, this is easy, because the Types involved do not require implementing ICloneable.

You can just do this:
Dictionary<int, string> dict1 = new Dictionary<int, string>(dict2);
You are incorrect when you assert removing the KeyValuePair from dict1 would affect dict2.
   
Comments
lmoelleb 17-May-19 10:58am
   
Be careful with ICloneable - it does not specify if a clone is deep or shallow.
BillWoodruff 17-May-19 12:17pm
   
Since I would only implement ICloneable when the Types I was using required a deep copy, I don't quite understand what point you are making here. Please say more.
lmoelleb 17-May-19 13:14pm
   
Implementing it as a deep copy is your preference. It is not something that is prescribed by the interface nor its documentation (on the contrary). This means every time you see the interface you have to think "is this one of my deep clones, or do I reference something written by another guy who might have done something else". To me, the interface just isn't worth using when I have to deal with potential future problems.
BillWoodruff 17-May-19 20:28pm
   
Implementing ICloneable is not a preference: it is a requirement when you want to deep copy complex, mutable objects.

It's not the only tool: you can use binary serialization. I suggest you study what ICloneable is, and what it means, rather than fantasizing about imaginary problems. While MS suggests ICloneable not be used in public API's, that has nothing too do with this thread.

https://docs.microsoft.com/en-us/dotnet/api/system.icloneable?redirectedfrom=MSDN&view=netframework-4.8
lmoelleb 18-May-19 3:03am
   
Quoting from the very link you are providing: "It does not specify whether the cloning operation performs a deep copy, a shallow copy, or something in between". There is no built in interface that guaranties deep clones in .NET. Sure you can use ICloneable for it, just be aware that simply because an object implements ICloneable, you can't guarantie it is a deep copy without further information (you wrote it yourself, it is documented, you read the code, …). You call that an imaginary problem. I call it something to be aware of so it does not become a real problem. I have done my share of cloning, including everything from cloning in the constructor over ICloneable, custom IDeepCloneable etc all the way to emitted code with reflection. Can you please point me in the direction of what additional information I can study on this subject?
BillWoodruff 18-May-19 3:10am
   
We are, I am afraid, on two different frequencies, here, and I am wasting my time trying to clarify that :) What you are saying appears to me both obvious, and also quite off-topic given what this thread is about.

Implementing interfaces only guarantees the presence of structures with certain signatures: of course, you can make a bloody mess with them.
Maciej Los 17-May-19 16:07pm
   
5ed!

If you wish to update only the items that have changed rather than make a new copy on every update, you could do something like this.


C#
 var missingKeys = dictA.Where(p => !dictB.ContainsKey(p.Key));
 var missingValues = dictA.Where(p => dictB.ContainsKey(p.Key) && dictB[p.Key]!=p.Value);
foreach(var p in missingKeys)
 {
     dictB.Add(p.Key, p.Value);
 }
 foreach (var p in missingValues)
 {
     dictB[p.Key]=p.Value;
 }
   
Here is a solution that will:
1. create the dictionary and load the data
2. backup (serialize) the dictionary to a string as we don't need to access it
3. remove an item
4. restores the original dictionary
C#
class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("-- start --");

        var dict1 = new Dictionary<int, string>
        {
            [0] = "ABC",
            [1] = "DEF",
            [2] = "GHI",
        };

        foreach (var item in dict1)
            Console.WriteLine($"{item.Key} = {item.Value}");

        Console.WriteLine("-- serialize --");

        var bkup = JsonConvert.SerializeObject(dict1);

        Console.WriteLine(bkup);


        Console.WriteLine("--remove item --");

        dict1.Remove(1);

        foreach (var item in dict1)
            Console.WriteLine($"{item.Key} = {item.Value}");

        Console.WriteLine("--restore --");
        dict1 = JsonConvert.DeserializeObject<Dictionary<int, string>>(bkup);

        foreach (var item in dict1)
            Console.WriteLine($"{item.Key} = {item.Value}");

        Console.ReadKey();
    }
}

And the output is:
-- start --
0 = ABC
1 = DEF
2 = GHI
-- serialize --
{"0":"ABC","1":"DEF","2":"GHI"}
--remove item --
0 = ABC
2 = GHI
--restore --
0 = ABC
1 = DEF
2 = GHI

For this eample I used NewtonSoft JSON library. You can learn more about this library here: [^]
   

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900