If your entire object graph is serialisable, my experience up to now
is that deep cloning is much easier and maintainable using in-memory
binary serialisation.
public static object DeepClone(object obj)
{
if (obj == null)
return null;
BinaryFormatter bf = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream())
{
bf.Serialize(ms, obj);
ms.Position = 0;
return bf.Deserialize(ms);
}
}
Simple unit test:
[Test()]
public void DeepCloneTest()
{
Assert.IsNull(PC.Utilities.DeepClone(null));
DummyCloneable data = new DummyCloneable();
DummyCloneable clone = (DummyCloneable) PC.Utilities.DeepClone(data);
Assert.IsTrue(data.CheckDeepClone(clone));
}
[Serializable()]
private class DummyCloneable
{
public int Data1;
public string Data2;
public object Data3;
public List<int> Data4;
public List<List<int>> Data5;
public Dictionary<string, object> Data6;
public DummyCloneable()
{
Data1 = 123;
Data2 = "foo";
Data3 = new object();
Data4 = new List<int>(new int[] {1, 2, 3, 4, 5});
Data5 = new List<List<int>>();
Data5.Add(new List<int>(new int[] { 1, 2, 3, 4, 5 }));
Data5.Add(new List<int>(new int[] { 1, 2, 3, 4, 5 }));
Data5.Add(new List<int>(new int[] { 1, 2, 3, 4, 5 }));
Data6 = new Dictionary<string, object>();
Data6["key1"] = "value1";
Data6["key2"] = 123;
Data6["key3"] = 123.456D;
Data6["key4"] = new object();
Data6["key5"] = Data5;
}
public bool CheckDeepClone(DummyCloneable obj)
{
if (obj.Data1 != this.Data1)
return false;
if (obj.Data2 != this.Data2)
return false;
if (obj.Data3.Equals(this.Data3))
return false;
if (obj.Data4.Equals(this.Data4))
return false;
for (int i = 0; i < this.Data4.Count; i++)
if (obj.Data4[i] != this.Data4[i])
return false;
if (obj.Data5.Equals(this.Data5))
return false;
for (int i = 0; i < this.Data5.Count; i++)
{
if (obj.Data5[i].Equals(this.Data5[i]))
return false;
for (int j = 0; j < this.Data5[i].Count; j++)
if (obj.Data5[i][j] != this.Data5[i][j])
return false;
}
if (obj.Data6.Equals(this.Data6))
return false;
if (((string) obj.Data6["key1"]) != ((string) this.Data6["key1"]))
return false;
if (((int) obj.Data6["key2"]) != ((int) this.Data6["key2"]))
return false;
if (((double) obj.Data6["key3"]) != ((double) this.Data6["key3"]))
return false;
if (obj.Data6["key4"].Equals(this.Data6["key4"]))
return false;
List<List<int>> objValue5 = (List<List<int>>) obj.Data6["key5"];
List<List<int>> thisValue5 = (List<List<int>>) this.Data6["key5"];
if (objValue5.Equals(thisValue5))
return false;
if (!objValue5.Equals(obj.Data5))
return false;
for (int i = 0; i < thisValue5.Count; i++)
{
if (objValue5[i].Equals(thisValue5[i]))
return false;
for (int j = 0; j < thisValue5[i].Count; j++)
if (objValue5[i][j] != thisValue5[i][j])
return false;
}
return true;
}
}
On 10/30/07, David Nicholson <[EMAIL PROTECTED]> wrote:
> No I hadn't thought of it. I haven't used serialisation very much, so I'm
> a little wary about what might go on under the covers. Perhaps I shouldn't
> be.
>
> I take care to follow a process, i.e. add a member, add an initialiser and
> property if needed, add to Clone(). But as the class grows it would be
> nice to have an automated check that these things have been done. Test
> first doesn't work because you can't compile an initial failing test.
>
> Clone stands out because the effect of omitting a member is often subtle,
> whereas a missing property is obvious immediately.
>
> Thanks
> David.
>
>
>
> On Tue, 30 Oct 2007 16:03:38 +0800, =?ISO-8859-1?Q?S=E9bastien_Lorion?=
> <[EMAIL PROTECTED]> wrote:
>
> >Have you thought about using serialisation for deep cloning (using
> >MemoryStream) ?
> >
> >Sébastien
> >
> >On 10/29/07, David Nicholson <[EMAIL PROTECTED]> wrote:
> >> I have some classes where I provide a Clone() method to provide a deep
> >> copy of an instance, and would like to test that I haven't added a
> member
> >> to the class without also adding it to Clone().
> >>
> >> To test Clone() I set a non-default value for the member, then check
> that
> >> the cloned copy has that value. However if I forget to add it to Clone
> (),
> >> I'll probably also forget to add it to the test.
> >>
> >> Does anyone have a way to do this, other than the obvious one of being
> >> more disciplined?
> >>
> >> Thanks
> >> David.
> >>
> >> ===================================
> >> This list is hosted by DevelopMentor(R) http://www.develop.com
> >>
> >> View archives and manage your subscription(s) at
> http://discuss.develop.com
> >>
> >
> >
> >--
> >Sébastien
> >www.sebastienlorion.com
>
> ===================================
> This list is hosted by DevelopMentor(R) http://www.develop.com
>
> View archives and manage your subscription(s) at http://discuss.develop.com
>
--
Sébastien
www.sebastienlorion.com
===================================
This list is hosted by DevelopMentor® http://www.develop.com
View archives and manage your subscription(s) at http://discuss.develop.com