Deep Copy of OrderedDictionary - c#

What is the simplest way to create a deep copy of an OrderedDictionary? I tried making a new variable like this:
var copy = dict[x] as OrderedDictionary;
But if I update the values/keys in copy, the dictionary in dict[x] gets updated as well.
Edit: dict is another OrderedDictionary.

You should be able to use a generic deep cloning method. An example of deep cloning from msdn magazine:
Object DeepClone(Object original)
{
// Construct a temporary memory stream
MemoryStream stream = new MemoryStream();
// Construct a serialization formatter that does all the hard work
BinaryFormatter formatter = new BinaryFormatter();
// This line is explained in the "Streaming Contexts" section
formatter.Context = new StreamingContext(StreamingContextStates.Clone);
// Serialize the object graph into the memory stream
formatter.Serialize(stream, original);
// Seek back to the start of the memory stream before deserializing
stream.Position = 0;
// Deserialize the graph into a new set of objects
// and return the root of the graph (deep copy) to the caller
return (formatter.Deserialize(stream));
}

What type of objects are you storing in your dictionary ?
You'll need to iterate over the content of the Dictionary and clone/duplicate the contents in some way.
If your object implements ICloneable you could do something like,
Dictionary<int, MyObject> original = new Dictionary<int, MyObject>();
... code to populate original ...
Dictionary<int, MyObject> deepCopy = new Dictionary<int, MyObject>();
foreach(var v in a)
{
MyObject clone = v.Value.Clone();
b.Add(v.Key, clone);
}

I can't tell from your question if dict is a dictionary of dictionaries? The simplest way to make a deep copy of a collection is to iterate through its members and clone each one.
If your value implements ICloneable:
OrderedDictionary newDict = new OrderedDictionary();
foreach(DictionaryEntry entry in OriginalDictionary)
{
newDict[entry.Key] = entry.Value.Clone();
}
If your values can't be Clone()d, you'll have to copy them another way.
OrderedDictionary newDict = new OrderedDictionary();
foreach(DictionaryEntry entry in OriginalDictionary)
{
MyClass x = new MyClass();
x.myProp1 = entry.Value.myProp1 as primitive value;
x.myProp2 = entry.Value.myProp2 as primitive value;
newDict[entry.Key] = x;
}

Related

How to deep copy a Dictionary containing a List in C#?

I need to a make a deep copy of a Dictionary<string, List<int>>. I tried:
Dictionary<string, List<int>> tmpStudents =
new Dictionary<string, List<int>>(students);
but manipulating the values in tmpStudents is still changing those in students. It seems that the lists in tmpStudents are still referencing the lists in students, but I'm not sure how to remedy this without manually deep copying each list.
You need to deep-copy the lists as well; all you have done is copy the dictionary, but all of the list references are still shared between them.
This is fairly easy using LINQ:
var tmpStudents = students.ToDictionary(p => p.Key, p => p.Value.ToList());
Try this:
var tmpStudents = students.ToDictionary(x => x.Key, x => x.Value.ToList());
Because you have a List<int> and int is a value type this should work. Otherwise you have to create a deep copy for each value separately.
Serialize your Dictionary to a MemoryStream using a BinaryFormatter, and then deserialize it back to your variable:
using (MemoryStream ms = new MemoryStream())
{
IFormatter formatter = new BinaryFormatter();
formatter.Serialize(ms, oldStudants);
var newStudants = (Dictionary<String, List<int>>)formatter.Deserialize(ms);
}

How to assign List<T> without it being a reference to the original List<T>?

For example
List<string> name_list1 = new List<string>();
List<string> name_list2 = new List<string>();
later in the code:
name_list1.Add("McDonald");
name_list1.Add("Harveys");
name_list1.Add("Wendys");
name_list2 = name_list1; // I make a copy of namelist1 to namelist2
So, from this point I would like to keep adding element or making changes in name_list2 without affecting name_list1. How do I do that?
name_list2 = new List<string>(name_list1);
This will clone the list.
Edit: This solution only works for primitive types. For objects, see other responses below.
Another Options is : Deep Cloning
public static T DeepCopy<T>(T item)
{
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
formatter.Serialize(stream, item);
stream.Seek(0, SeekOrigin.Begin);
T result = (T)formatter.Deserialize(stream);
stream.Close();
return result;
}
so,
you can use :
name_list2 = DeepCopy<List<string>>(name_list1);
OR:
name_list2 = DeepCopy(name_list1);
will also work.
For Primitive Types you can do this:
List<string> CopyList = new List<string>(OriginalList);
For non-primitve/user-difined types you can do this:
List<Person> CopyList = new List<Person>();
foreach(var item in OriginalList)
{
CopyList.Add(new Person {
Name = item.Name,
Address = item.Address
});
}
name_list2 = new List<string>(name_list1); // Clone list into a different object
At this point, the two lists are different objects. You can add items to list2 without affecting list1
The problem is the assignment. Until the assignment name_list2 = name_list1;, you have two different List objects on the heap pointed to by the variables name_list1 and name_list2. You fill up name_list1, which is fine. But the assignment says, "make name_list2 point to the same object on the heap as name_list1." The List that name_list2 used to point to is no longer accessible and will be garbage collected. What you really want is to copy the contents of name_list1 into name_list2. You can do this with List.AddRange. Note that this will result in a "shallow" copy, which is fine for the example you cite, where the list contents are strings, but may not be what you want when the list members are more complex objects. It all depends on your needs.
Based on #Mrunal answer I created an extension method:
public static T Clone<T>(this T source)
{
// Don't serialize a null object, simply return the default for that object
if (source == null)
{
return default;
}
// initialize inner objects individually
// for example in default constructor some list property initialized with some values,
// but in 'source' these items are cleaned -
// without ObjectCreationHandling.Replace default constructor values will be added to result
var deserializeSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace };
return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source), deserializeSettings);
}
And you can call it like this:
L2 = L1.Select(x => x.Clone()).ToList();
I like linq for this...
If list elements are primitives or structures then...
L2 = L1.ToList()
If list elements are classes then...
L2 = L1.Select(x => x.Copy()).ToList();
Where Copy could simply be a shallow copy exposure of MemberWiseClone, or it could be some implementation of a deep copy.
I prefer Json converter method to serialize and deserialize, this way you don't have to mark the classes for serialization, especially you have numerous child classes.
https://www.newtonsoft.com/json/help/html/SerializingJSON.htm
Here is an alternative solution:
List<string> name_list1 = new List<string>();
List<string> name_list2 = new List<string>();
name_list1.Add("McDonald");
name_list1.Add("Harveys");
name_list1.Add("Wendys");
name_list2.AddRange(name_list1.ToArray());
The ToArray() method copies 'name_list1' to a new array, which we then add to name_list2 via the AddRange() method.
For primitive types:
List ClonedList = new list(OriginalList);
For non-primitive/User Defined types:
We need to perform a deep copy:
Deep Copy is used to make a complete deep copy of the internal reference types, for this we need to configure the object returned by MemberwiseClone().
Step1- In your class inherit from ICloneable:
public class MyClass:ICloneable
Step2- Implement method
public MyClass Clone()
{
MyClass MyClassObj =new MyClass();
MyClassObj.Property1 = this.Property1;
.
.
MyClassObj.Property_N = this.Property_N;
return MyClass;
}
Step3- now clone your List
List<MyClass> MyClassClone = new List<MyClass>();
for(i=0; i<Count; i++)
{
MyClassClone.Add(OriginalClaaObj[i].Clone());
}
This will make deep copy of each item of the object.
None of the above solutions worked for me when using lists of class objects.
This can be used for copying any object to another object with shared property names.
public static void ObjectToObject(object source, object destination)
{
// Purpose : Use reflection to set property values of objects that share the same property names.
Type s = source.GetType();
Type d = destination.GetType();
const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
var objSourceProperties = s.GetProperties(flags);
var objDestinationProperties = d.GetProperties(flags);
var propertyNames = objSourceProperties
.Select(c => c.Name)
.ToList();
foreach (var properties in objDestinationProperties.Where(properties => propertyNames.Contains(properties.Name)))
{
try
{
PropertyInfo piSource = source.GetType().GetProperty(properties.Name);
properties.SetValue(destination, piSource.GetValue(source, null), null);
}
catch (Exception ex)
{
throw;
}
}
}
public static List<T> CopyList<T>(this List<T> lst)
{
List<T> lstCopy = new List<T>();
foreach (var item in lst)
{
var instanceOfT = Activator.CreateInstance<T>();
ObjectToObject(item, instanceOfT);
lstCopy.Add(instanceOfT);
}
return lstCopy;
}
For lists use this:
list2 = list1.CopyList();
If both the lists are of the same complex type then you can do something like below:-
SomeClass List2 = new List();
List1.ForEach(u => List2.Add(u));
What I am doing is to loop through each element of List1 and keep adding it to List2.
I believe this is the shortest way to do it.
While it could be potential performance-threat solution, but it would copy the values property-by-property eloquently.
using Newstonsoft.Json;
ClassA classA = new ClassA();
ClassA classACopyWithoutReference = JsonConvert.DeserializeObject<ClassA>(JsonConvert.SerializeObject(classA));
this solution works For complex objects (Replace T with name of your Type):
list2 = list1.Concat(new List<T> { object }).ToList();
or:
list2 = list1.ToArray().Append(object).ToList()
You can clone the complex object by serialize and deserialize it, it will remove you object reference and create new object without reference
using Newstonsoft.Json;
List<string> name_list1 = new List<string>();
name_list1.Add("McDonald");
name_list1.Add("Harveys");
name_list1.Add("Wendys");
name_list2 = name_list1;
List<string> name_list2 = JsonConvert.DeserializeObject<List<string>>
(JsonConvert.SerializeObject(name_list1)); // Ii make a copy of namelist1 to namelist2
this is working for me using LINQ...
lst1= lst2.ToList();

Write Dictionary which has Objects to file

I have such dictionary Dictionary<string, object>, dictionary holds string keys and objects as values. I need to save and later load such dictionary. What would be best method to do that?
You can use this serializable Dictionary<TKey, TVal>(tested):
http://www.dacris.com/blog/2010/07/31/c-serializable-dictionary-a-working-example/
Dictionary<String, Object> otherDictionary = new Dictionary<String, Object>();
otherDictionary.Add("Foo", new List<String>() { "1st Foo","2nd Foo","3rd Foo" });
var dict = new SerializableDictionary<String, Object>(otherDictionary);
write it to a file:
using (FileStream fileStream = new FileStream("test.binary", FileMode.Create))
{
IFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
bf.Serialize(fileStream, dict);
}
read it from a file:
using (FileStream fileStream = new FileStream("test.binary", FileMode.Open))
{
IFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
dict = (SerializableDictionary<String, Object>)bf.Deserialize(fileStream);
}
Note: Of course you don't need to create a second Dictionary. You can use the SerializableDictionary at the first place. That should just demonstrate how to use it with an already existing Dictionary.
You can use NewtonSoft Json.net: http://james.newtonking.com/projects/json-net.aspx.
It is flexible and very friendly.
How about serializing it to XML?
http://support.microsoft.com/kb/815813
object yourType = new Object();
System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(yourType.GetType());
x.Serialize(Console.Out,yourType);
If you don't mind adding in an extra dependency, you can use protobuf.net. This has the benefit of being fast (definitely faster than the XML serializer approach), and it works on the bog standard Dictionary.
Reference it in your assembly, then the following shows how to use it with a MemoryStream:
class Program
{
static void Main(string[] args)
{
Dictionary<int, string> dict = new Dictionary<int, string>();
for (int i = 0; i < 10; i++)
{
dict[i] = i.ToString();
}
using (var ms = new MemoryStream())
{
ProtoBuf.Serializer.Serialize(ms, dict);
ms.Seek(0, SeekOrigin.Begin);
var dict2 = ProtoBuf.Serializer.Deserialize<Dictionary<int, string>>(ms);
}
}
}
So long as both the key and value type for the dictionary are serializable by protobuf.net, this will work.
EDIT:
If you want to use this approach, you have to make your key and value object's class serializable by ProtoBuf. In short, attach [ProtoContract] to the class, and attach e.g. [ProtoMember(1)] to each Property you want to be serialized. See the website for more details. Note both string and int are serializable out of the box.

How to deep copy a matrix in C#?

I got a List<List<CustomClass>>, where CustomClass is a reference type.
I need to make a full deep copy of this matrix into a new one. Since I want a deep copy, each CustomClass object in the matrix has to be copied into the new matrix.
How would you do that in an efficient way?
For a CustomClass that implements ICloneable, this isn't very difficult:
var myList = new List<List<CustomClass>>();
//populate myList
var clonedList = new List<List<CustomClass>>();
//here's the beef
foreach(var sublist in myList)
{
var newSubList = new List<CustomClass>();
clonedList.Add(newSubList);
foreach(var item in sublist)
newSublist.Add((CustomClass)(item.Clone()));
}
You can make this work in a similar way with any "DeepCopy"-type method, if you feel you don't want to implement ICloneable (I would recommend using the built-in interface though).
One easier way to serialize the whole object and then deserialize it again, try this extension method:
public static T DeepClone<T>(this T source)
{
if (!typeof(T).IsSerializable)
{
throw new ArgumentException("The type must be serializable.", "source");
}
// Don't serialize a null object, simply return the default for that object
if (Object.ReferenceEquals(source, null))
{
return default(T);
}
IFormatter formatter = new BinaryFormatter();
Stream stream = new MemoryStream();
using (stream)
{
formatter.Serialize(stream, source);
stream.Seek(0, SeekOrigin.Begin);
return (T)formatter.Deserialize(stream);
}
}
USAGE
List<List<CustomClass>> foobar = GetListOfListOfCustomClass();
List<List<CustomClass>> deepClonedObject = foobar.DeepClone();
There are two possibilities:
Implement the ICloneable interface on your CustomClass, then you can clone your objects.
If the class can be serialized, serialize it to a memory stream and deserialize it from there. That will create a copy of it.
I would prefer to take the first alternative, because I think serializing / deserializing is slower than cloning via ICloneable.
Assuming you have a Copy method which can duplicate CustomClass objects:
var newMatrix = oldMatrix
.Select(subList => subList.Select(custom => Copy(custom)).ToList())
.ToList();

c# List<myObject> myList.copyTo() keeps a reference?

I've got a List and I used .copyTo() method. So it copies my List into one dimensional array.
So I loop this array and add each myObject to another List, then I'm changing things in this new List.
After this I'm showing the difference between the new values in my second List and the old values that are in my first List. But there is always no difference. So I'm thinking that the copyTo() method keeps a reference.
Are there other methods that doesn't keep a reference?
Yes. .CopyTo() performs a shallow copy, which means it copies the references. What you need is a deep copy, by cloning each object.
The best way is to make you myObject class implement IClonable
public class YourClass
{
public object Clone()
{
using (var ms = new MemoryStream())
{
var bf = new BinaryFormatter();
bf.Serialize(ms, this);
ms.Position = 0;
object obj = bf.Deserialize(ms);
ms.Close();
return obj;
}
}
}
Then you can cole .Clone() on each object and add that to a new List.
List<YourClass> originalItems = new List<YourClass>() { new YourClass() };
List<YourClass> newItemList = originalItems.Select(x => x.Clone() as YourClass).ToList();
If you've got a List of reference types, and you use the the CopyTo method to copy to an array, the contents of the List which are references will be copied across, so when you modify the objects in your array, they'll still refer to the same objects on the heap which are referenced from your list.

Categories

Resources