{"id":2912,"date":"2009-09-25T10:09:00","date_gmt":"2009-09-25T10:09:00","guid":{"rendered":"https:\/\/test.simple-talk.com\/uncategorized\/cloning-objects-the-quick-and-dirty-way\/"},"modified":"2016-07-28T10:49:46","modified_gmt":"2016-07-28T10:49:46","slug":"cloning-objects-the-quick-and-dirty-way","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/blogs\/cloning-objects-the-quick-and-dirty-way\/","title":{"rendered":"Cloning objects the quick and dirty way"},"content":{"rendered":"<p>Working in .NET, a lot of the objects I use implement ISerializable &#8211; very handy when it comes to throwing them around using .NET Remoting and the like. In my slightly more evil (or is it lazy?) moments, I tend to &#8220;re-purpose&#8221; this for a lightweight clone mechanism&#8230;<\/p>\n<p>It&#8217;s quite common when writing test code to be able to do a deep copy of an object &#8211; maybe to keep a copy of its state before performing an operation to then compare it again later, or maybe to &#8220;subclass&#8221; an existing object, overriding a given property with something else. Even preventing certain properties going over the wire or to disk because they aren&#8217;t required, all without the original object knowing anything of the devious things going on.<\/p>\n<p>The problem is, there&#8217;s no generic deep copy facility available in .NET (correctly so), and I generally don&#8217;t want to have to implement IClonable on everything as well. What to do?<\/p>\n<p>Assume I have a couple of little classes, Outer, and Inner, where Outer has a property of type Inner:<\/p>\n<p>&#160;&#160;&#160; [Serializable]<br \/>&#160;&#160;&#160; class Outer : ISerializable<br \/>&#160;&#160;&#160; {<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; public Inner Inner { get; set; }<\/p>\n<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160; public Outer() { }<\/p>\n<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160; public Outer(SerializationInfo info, StreamingContext context)<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; {<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Inner = (Inner)info.GetValue(&#8220;Inner&#8221;, typeof(Inner));<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; }<\/p>\n<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160; public void GetObjectData(SerializationInfo info, StreamingContext context)<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; {<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; info.AddValue(&#8220;Inner&#8221;, Inner);<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; }<br \/>&#160;&#160;&#160; }<\/p>\n<p>&#160;&#160;&#160; [Serializable]<br \/>&#160;&#160;&#160; class Inner : ISerializable<br \/>&#160;&#160;&#160; {<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; public Inner() { }<\/p>\n<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160; public Inner(SerializationInfo info, StreamingContext context) { }<\/p>\n<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160; public void GetObjectData(SerializationInfo info, StreamingContext context) { }<br \/>&#160;&#160;&#160; }<\/p>\n<p>My first solution was along these lines &#8211; very compact, and seemed to work:<\/p>\n<p>&#160;&#160;&#160; class ClonedOuter : Outer<br \/>&#160;&#160;&#160; {<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; public ClonedOuter(Outer o)<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; : base(GetSerializationInfo(o), new StreamingContext ())<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; { }<\/p>\n<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160; private static SerializationInfo GetSerializationInfo(Outer o)<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; {<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; SerializationInfo info = new SerializationInfo(typeof(Outer), new FormatterConverter());<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; o.GetObjectData(info, new StreamingContext());<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return info;<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; }<br \/>&#160;&#160;&#160; }<\/p>\n<p>The theory went that Outer would serialize its state to the SerializationInfo I provided in GetSerializationInfo, and that would then get passed to the deserialization constructor of Outer via the base(&#8230;) call, giving a nicely duplicated object. And it did! But then I hit a problem:<\/p>\n<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Outer clone1 = new ClonedOuter(original);<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Console.WriteLine(&#8220;clone1.Inner == original.Inner: &#8221; + (clone1.Inner == original.Inner)); \/\/ Prints true!<\/p>\n<p>Whilst the Outer object was being cloned, the Inner one was not &#8211; it was simply the same object. The reason for this is hinted at <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ty01x675%28VS.85%29.aspx\">in the documentation<\/a>: &#8220;Objects are reconstructed from the inside out.&#8221; The GetObjectData of Inner wasn&#8217;t even being called, let alone being used.<\/p>\n<p>Back to the drawing board. This time, a slightly more &#8220;authorized&#8221; use of serialization:<\/p>\n<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160; public static Outer Clone(Outer o)<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; {<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; BinaryFormatter bf = new BinaryFormatter();<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; using (MemoryStream ms = new MemoryStream())<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; bf.Serialize(ms, o);<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ms.Seek(0, SeekOrigin.Begin);<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return (Outer)bf.Deserialize(ms);<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; }<\/p>\n<p>Here we actually force the object graph to be serialized to a MemoryStream (basically a wrapper around a byte[]), and the results are as expected. Much better. But it&#8217;s not perfect: I quite like the ability to have a &#8220;copy constructor&#8221; of the form &#8220;new ObjectyThing(ObjectyThing source)&#8221;, and the static Clone method doesn&#8217;t give me the opportunity to subclass the cloned copy.<\/p>\n<p>So then you combine both approaches:<\/p>\n<p>&#160;&#160;&#160; class ClonedOuter2 : Outer<br \/>&#160;&#160;&#160; {<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; public ClonedOuter2(Outer o)<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; : base(GetSerializationInfo(Clone(o)), new StreamingContext())<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; { }<\/p>\n<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160; public static Outer Clone(Outer o)<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; {<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; BinaryFormatter bf = new BinaryFormatter();<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; using (MemoryStream ms = new MemoryStream())<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; bf.Serialize(ms, o);<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ms.Seek(0, SeekOrigin.Begin);<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return (Outer)bf.Deserialize(ms);<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; }<\/p>\n<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160; private static SerializationInfo GetSerializationInfo(Outer o)<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; {<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; SerializationInfo info = new SerializationInfo(typeof(Outer), new FormatterConverter());<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; o.GetObjectData(info, new StreamingContext());<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return info;<br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; }<br \/>&#160;&#160;&#160; }<\/p>\n<p>I dread to think of the efficiency of this&#8230; \ud83d\ude42<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Working in .NET, a lot of the objects I use implement ISerializable &#8211; very handy when it comes to throwing them around using .NET Remoting and the like. In my slightly more evil (or is it lazy?) moments, I tend to &#8220;re-purpose&#8221; this for a lightweight clone mechanism&#8230; It&#8217;s quite common when writing test code&#8230;&hellip;<\/p>\n","protected":false},"author":169277,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[2],"tags":[],"coauthors":[],"class_list":["post-2912","post","type-post","status-publish","format-standard","hentry","category-blogs"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/2912","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/169277"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=2912"}],"version-history":[{"count":2,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/2912\/revisions"}],"predecessor-version":[{"id":41807,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/2912\/revisions\/41807"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=2912"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=2912"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=2912"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=2912"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}