From 15300676ba595291e3bf81b709778125ad8cab50 Mon Sep 17 00:00:00 2001 From: Markus Ewald Date: Wed, 8 Feb 2012 17:13:08 +0000 Subject: [PATCH] Streamlined the cloning API: whether a property-based clone is performed is no longer indicated through a parameter, but by calling the appropriate method git-svn-id: file:///srv/devel/repo-conversion/nusu@245 d2e56fa2-650e-0410-a79f-9358c0239efd --- Source/Cloning/ExpressionTreeCloner.Test.cs | 26 ++-- Source/Cloning/ExpressionTreeCloner.cs | 128 ++++++++++++-------- Source/Cloning/ICloneFactory.cs | 73 ++++++++--- Source/Cloning/ReflectionCloner.Test.cs | 26 ++-- Source/Cloning/ReflectionCloner.cs | 114 ++++++++++------- Source/Cloning/SerializationCloner.Test.cs | 16 +-- Source/Cloning/SerializationCloner.cs | 71 ++++++----- 7 files changed, 277 insertions(+), 177 deletions(-) diff --git a/Source/Cloning/ExpressionTreeCloner.Test.cs b/Source/Cloning/ExpressionTreeCloner.Test.cs index cfb2c67..771c3ff 100644 --- a/Source/Cloning/ExpressionTreeCloner.Test.cs +++ b/Source/Cloning/ExpressionTreeCloner.Test.cs @@ -40,7 +40,7 @@ namespace Nuclex.Support.Cloning { [Test] public void PrimitiveTypesCanBeCloned() { int original = 12345; - int clone = this.cloneFactory.DeepClone(original, false); + int clone = this.cloneFactory.DeepFieldClone(original); Assert.AreEqual(original, clone); } @@ -48,7 +48,7 @@ namespace Nuclex.Support.Cloning { [Test] public void ReferenceTypesCanBeCloned() { var original = new TestReferenceType() { TestField = 123, TestProperty = 456 }; - TestReferenceType clone = this.cloneFactory.DeepClone(original, false); + TestReferenceType clone = this.cloneFactory.DeepFieldClone(original); Assert.AreNotSame(original, clone); Assert.AreEqual(original.TestField, clone.TestField); @@ -59,7 +59,7 @@ namespace Nuclex.Support.Cloning { [Test] public void PrimitiveArraysCanBeCloned() { var original = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; - int[] clone = this.cloneFactory.DeepClone(original, false); + int[] clone = this.cloneFactory.DeepFieldClone(original); Assert.AreNotSame(original, clone); CollectionAssert.AreEqual(original, clone); @@ -71,7 +71,7 @@ namespace Nuclex.Support.Cloning { var original = new TestReferenceType[] { new TestReferenceType() { TestField = 123, TestProperty = 456 } }; - TestReferenceType[] clone = this.cloneFactory.ShallowClone(original, false); + TestReferenceType[] clone = this.cloneFactory.ShallowFieldClone(original); Assert.AreSame(original[0], clone[0]); } @@ -84,7 +84,7 @@ namespace Nuclex.Support.Cloning { new TestReferenceType() { TestField = 123, TestProperty = 456 } } }; - TestReferenceType[,] clone = this.cloneFactory.DeepClone(original, false); + TestReferenceType[,] clone = this.cloneFactory.DeepFieldClone(original); Assert.AreNotSame(original[0, 0], clone[0, 0]); Assert.AreEqual(original[0, 0].TestField, clone[0, 0].TestField); @@ -95,7 +95,7 @@ namespace Nuclex.Support.Cloning { [Test] public void GenericListsCanBeCloned() { var original = new List(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }); - List clone = this.cloneFactory.DeepClone(original, false); + List clone = this.cloneFactory.DeepFieldClone(original); CollectionAssert.AreEqual(original, clone); } @@ -105,7 +105,7 @@ namespace Nuclex.Support.Cloning { public void GenericDictionariesCanBeCloned() { var original = new Dictionary(); original.Add(1, "one"); - Dictionary clone = this.cloneFactory.DeepClone(original, false); + Dictionary clone = this.cloneFactory.DeepFieldClone(original); Assert.AreEqual("one", clone[1]); } @@ -116,7 +116,7 @@ namespace Nuclex.Support.Cloning { [Test] public void ShallowFieldBasedClonesOfValueTypesCanBeMade() { HierarchicalValueType original = CreateValueType(); - HierarchicalValueType clone = this.cloneFactory.ShallowClone(original, false); + HierarchicalValueType clone = this.cloneFactory.ShallowFieldClone(original); VerifyClone(ref original, ref clone, isDeepClone: false, isPropertyBasedClone: false); } @@ -126,7 +126,7 @@ namespace Nuclex.Support.Cloning { [Test] public void ShallowFieldBasedClonesOfReferenceTypesCanBeMade() { HierarchicalReferenceType original = CreateReferenceType(); - HierarchicalReferenceType clone = this.cloneFactory.ShallowClone(original, false); + HierarchicalReferenceType clone = this.cloneFactory.ShallowFieldClone(original); VerifyClone(original, clone, isDeepClone: false, isPropertyBasedClone: false); } @@ -136,7 +136,7 @@ namespace Nuclex.Support.Cloning { [Test] public void DeepFieldBasedClonesOfValueTypesCanBeMade() { HierarchicalValueType original = CreateValueType(); - HierarchicalValueType clone = this.cloneFactory.DeepClone(original, false); + HierarchicalValueType clone = this.cloneFactory.DeepFieldClone(original); VerifyClone(ref original, ref clone, isDeepClone: true, isPropertyBasedClone: false); } @@ -146,7 +146,7 @@ namespace Nuclex.Support.Cloning { [Test] public void DeepFieldBasedClonesOfReferenceTypesCanBeMade() { HierarchicalReferenceType original = CreateReferenceType(); - HierarchicalReferenceType clone = this.cloneFactory.DeepClone(original, false); + HierarchicalReferenceType clone = this.cloneFactory.DeepFieldClone(original); VerifyClone(original, clone, isDeepClone: true, isPropertyBasedClone: false); } @@ -178,7 +178,7 @@ namespace Nuclex.Support.Cloning { [Test] public void DeepPropertyBasedClonesOfValueTypesCanBeMade() { HierarchicalValueType original = CreateValueType(); - HierarchicalValueType clone = this.cloneFactory.DeepClone(original, true); + HierarchicalValueType clone = this.cloneFactory.DeepPropertyClone(original); VerifyClone(ref original, ref clone, isDeepClone: true, isPropertyBasedClone: true); } @@ -188,7 +188,7 @@ namespace Nuclex.Support.Cloning { [Test] public void DeepPropertyBasedClonesOfReferenceTypesCanBeMade() { HierarchicalReferenceType original = CreateReferenceType(); - HierarchicalReferenceType clone = this.cloneFactory.DeepClone(original, true); + HierarchicalReferenceType clone = this.cloneFactory.DeepPropertyClone(original); VerifyClone(original, clone, isDeepClone: true, isPropertyBasedClone: true); } diff --git a/Source/Cloning/ExpressionTreeCloner.cs b/Source/Cloning/ExpressionTreeCloner.cs index c53f9f5..1c826ec 100644 --- a/Source/Cloning/ExpressionTreeCloner.cs +++ b/Source/Cloning/ExpressionTreeCloner.cs @@ -45,66 +45,32 @@ namespace Nuclex.Support.Cloning { /// /// Type of the object that will be cloned /// Object that will be cloned - /// - /// Whether to clone the object based on its properties only - /// /// A deep clone of the provided object - public static TCloned DeepClone( - TCloned objectToClone, bool usePropertyBasedClone - ) { + public static TCloned DeepFieldClone(TCloned objectToClone) { object objectToCloneAsObject = objectToClone; if(objectToCloneAsObject == null) { return default(TCloned); } - Func cloner; - if(usePropertyBasedClone) { - cloner = getOrCreateDeepPropertyBasedCloner(typeof(TCloned)); - } else { - cloner = getOrCreateDeepFieldBasedCloner(typeof(TCloned)); - } + Func cloner = getOrCreateDeepFieldBasedCloner(typeof(TCloned)); return (TCloned)cloner(objectToCloneAsObject); } - /// - /// Creates a shallow clone of the specified object, reusing any referenced objects - /// - /// Type of the object that will be cloned - /// Object that will be cloned - /// - /// Whether to clone the object based on its properties only - /// - /// A shallow clone of the provided object - public static TCloned ShallowClone( - TCloned objectToClone, bool usePropertyBasedClone - ) { - object objectToCloneAsObject = objectToClone; - if(objectToCloneAsObject == null) { - return default(TCloned); - } - - if(usePropertyBasedClone) { - throw new NotImplementedException("Not implemented yet"); - } else { - Func cloner = getOrCreateShallowFieldBasedCloner(typeof(TCloned)); - return (TCloned)cloner(objectToCloneAsObject); - } - } - /// /// Creates a deep clone of the specified object, also creating clones of all /// child objects being referenced /// /// Type of the object that will be cloned /// Object that will be cloned - /// - /// Whether to clone the object based on its properties only - /// /// A deep clone of the provided object - TCloned ICloneFactory.DeepClone( - TCloned objectToClone, bool usePropertyBasedClone - ) { - return ExpressionTreeCloner.DeepClone(objectToClone, usePropertyBasedClone); + public static TCloned DeepPropertyClone(TCloned objectToClone) { + object objectToCloneAsObject = objectToClone; + if(objectToCloneAsObject == null) { + return default(TCloned); + } + + Func cloner = getOrCreateDeepPropertyBasedCloner(typeof(TCloned)); + return (TCloned)cloner(objectToCloneAsObject); } /// @@ -112,14 +78,74 @@ namespace Nuclex.Support.Cloning { /// /// Type of the object that will be cloned /// Object that will be cloned - /// - /// Whether to clone the object based on its properties only - /// /// A shallow clone of the provided object - TCloned ICloneFactory.ShallowClone( - TCloned objectToClone, bool usePropertyBasedClone - ) { - return ExpressionTreeCloner.ShallowClone(objectToClone, usePropertyBasedClone); + public static TCloned ShallowFieldClone(TCloned objectToClone) { + object objectToCloneAsObject = objectToClone; + if(objectToCloneAsObject == null) { + return default(TCloned); + } + + Func cloner = getOrCreateShallowFieldBasedCloner(typeof(TCloned)); + return (TCloned)cloner(objectToCloneAsObject); + } + + /// + /// Creates a shallow clone of the specified object, reusing any referenced objects + /// + /// Type of the object that will be cloned + /// Object that will be cloned + /// A shallow clone of the provided object + public static TCloned ShallowPropertyClone(TCloned objectToClone) { + object objectToCloneAsObject = objectToClone; + if(objectToCloneAsObject == null) { + return default(TCloned); + } + + throw new NotImplementedException("Not implemented yet"); + Func cloner = getOrCreateShallowFieldBasedCloner(typeof(TCloned)); + return (TCloned)cloner(objectToCloneAsObject); + } + + /// + /// Creates a shallow clone of the specified object, reusing any referenced objects + /// + /// Type of the object that will be cloned + /// Object that will be cloned + /// A shallow clone of the provided object + TCloned ICloneFactory.ShallowFieldClone(TCloned objectToClone) { + return ExpressionTreeCloner.ShallowFieldClone(objectToClone); + } + + /// + /// Creates a shallow clone of the specified object, reusing any referenced objects + /// + /// Type of the object that will be cloned + /// Object that will be cloned + /// A shallow clone of the provided object + TCloned ICloneFactory.ShallowPropertyClone(TCloned objectToClone) { + return ExpressionTreeCloner.ShallowPropertyClone(objectToClone); + } + + /// + /// Creates a deep clone of the specified object, also creating clones of all + /// child objects being referenced + /// + /// Type of the object that will be cloned + /// Object that will be cloned + /// A deep clone of the provided object + TCloned ICloneFactory.DeepFieldClone(TCloned objectToClone) { + return ExpressionTreeCloner.DeepFieldClone(objectToClone); + } + + /// + /// Creates a deep clone of the specified object, also creating clones of all + /// child objects being referenced + /// + /// Type of the object that will be cloned + /// Object that will be cloned + /// A deep clone of the provided object + TCloned ICloneFactory.DeepPropertyClone(TCloned objectToClone) { + return ExpressionTreeCloner.DeepPropertyClone(objectToClone); } #if false diff --git a/Source/Cloning/ICloneFactory.cs b/Source/Cloning/ICloneFactory.cs index 0db10fc..6e6b635 100644 --- a/Source/Cloning/ICloneFactory.cs +++ b/Source/Cloning/ICloneFactory.cs @@ -26,39 +26,74 @@ namespace Nuclex.Support.Cloning { public interface ICloneFactory { /// - /// Creates a deep clone of the specified object, also creating clones of all - /// child objects being referenced + /// Creates a shallow clone of the specified object, reusing any referenced objects /// /// Type of the object that will be cloned /// Object that will be cloned - /// - /// Whether to clone the object based on its properties only - /// - /// A deep clone of the provided object + /// A shallow clone of the provided object /// - /// A property-based clone is useful if you're using dynamically generated proxies, - /// such as when working with entities returned by an ORM like NHibernate. - /// When not using a property-based clone, internal proxy fields would be cloned - /// and might cause problems with the ORM. + /// Field-based clones are guaranteed to be complete - there will be no missed + /// members. This type of clone is also able to clone types that do not provide + /// a default constructor. /// - TCloned DeepClone(TCloned objectToClone, bool usePropertyBasedClone); + TCloned ShallowFieldClone(TCloned objectToClone); /// /// Creates a shallow clone of the specified object, reusing any referenced objects /// /// Type of the object that will be cloned /// Object that will be cloned - /// - /// Whether to clone the object based on its properties only - /// /// A shallow clone of the provided object /// - /// A property-based clone is useful if you're using dynamically generated proxies, - /// such as when working with entities returned by an ORM like NHibernate. - /// When not using a property-based clone, internal proxy fields would be cloned - /// and might cause problems with the ORM. + /// + /// A property-based clone is useful if you're using dynamically generated proxies, + /// such as when working with entities returned by an ORM like NHibernate. + /// When not using a property-based clone, internal proxy fields would be cloned + /// and might cause problems with the ORM. + /// + /// + /// Property-based clones require a default constructor because there's no guarantee + /// that all fields will are assignable through properties and starting with + /// an uninitialized object is likely to end up with a broken clone. + /// /// - TCloned ShallowClone(TCloned objectToClone, bool usePropertyBasedClone); + TCloned ShallowPropertyClone(TCloned objectToClone); + + /// + /// Creates a deep clone of the specified object, also creating clones of all + /// child objects being referenced + /// + /// Type of the object that will be cloned + /// Object that will be cloned + /// A deep clone of the provided object + /// + /// Field-based clones are guaranteed to be complete - there will be no missed + /// members. This type of clone is also able to clone types that do not provide + /// a default constructor. + /// + TCloned DeepFieldClone(TCloned objectToClone); + + /// + /// Creates a deep clone of the specified object, also creating clones of all + /// child objects being referenced + /// + /// Type of the object that will be cloned + /// Object that will be cloned + /// A deep clone of the provided object + /// + /// + /// A property-based clone is useful if you're using dynamically generated proxies, + /// such as when working with entities returned by an ORM like NHibernate. + /// When not using a property-based clone, internal proxy fields would be cloned + /// and might cause problems with the ORM. + /// + /// + /// Property-based clones require a default constructor because there's no guarantee + /// that all fields will are assignable through properties and starting with + /// an uninitialized object is likely to end up with a broken clone. + /// + /// + TCloned DeepPropertyClone(TCloned objectToClone); } diff --git a/Source/Cloning/ReflectionCloner.Test.cs b/Source/Cloning/ReflectionCloner.Test.cs index 1966a69..864e3ea 100644 --- a/Source/Cloning/ReflectionCloner.Test.cs +++ b/Source/Cloning/ReflectionCloner.Test.cs @@ -40,7 +40,7 @@ namespace Nuclex.Support.Cloning { [Test] public void PrimitiveTypesCanBeCloned() { int original = 12345; - int clone = this.cloneFactory.ShallowClone(original, false); + int clone = this.cloneFactory.ShallowFieldClone(original); Assert.AreEqual(original, clone); } @@ -50,7 +50,7 @@ namespace Nuclex.Support.Cloning { var original = new TestReferenceType[] { new TestReferenceType() { TestField = 123, TestProperty = 456 } }; - TestReferenceType[] clone = this.cloneFactory.ShallowClone(original, false); + TestReferenceType[] clone = this.cloneFactory.ShallowFieldClone(original); Assert.AreSame(original[0], clone[0]); } @@ -61,7 +61,7 @@ namespace Nuclex.Support.Cloning { var original = new TestReferenceType[] { new TestReferenceType() { TestField = 123, TestProperty = 456 } }; - TestReferenceType[] clone = this.cloneFactory.DeepClone(original, false); + TestReferenceType[] clone = this.cloneFactory.DeepFieldClone(original); Assert.AreNotSame(original[0], clone[0]); Assert.AreEqual(original[0].TestField, clone[0].TestField); @@ -72,7 +72,7 @@ namespace Nuclex.Support.Cloning { [Test] public void GenericListsCanBeCloned() { var original = new List(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }); - List clone = this.cloneFactory.DeepClone(original, false); + List clone = this.cloneFactory.DeepFieldClone(original); CollectionAssert.AreEqual(original, clone); } @@ -82,7 +82,7 @@ namespace Nuclex.Support.Cloning { public void GenericDictionariesCanBeCloned() { var original = new Dictionary(); original.Add(1, "one"); - Dictionary clone = this.cloneFactory.DeepClone(original, false); + Dictionary clone = this.cloneFactory.DeepFieldClone(original); Assert.AreEqual("one", clone[1]); } @@ -93,7 +93,7 @@ namespace Nuclex.Support.Cloning { [Test] public void ShallowFieldBasedClonesOfValueTypesCanBeMade() { HierarchicalValueType original = CreateValueType(); - HierarchicalValueType clone = this.cloneFactory.ShallowClone(original, false); + HierarchicalValueType clone = this.cloneFactory.ShallowFieldClone(original); VerifyClone(ref original, ref clone, isDeepClone: false, isPropertyBasedClone: false); } @@ -103,7 +103,7 @@ namespace Nuclex.Support.Cloning { [Test] public void ShallowFieldBasedClonesOfReferenceTypesCanBeMade() { HierarchicalReferenceType original = CreateReferenceType(); - HierarchicalReferenceType clone = this.cloneFactory.ShallowClone(original, false); + HierarchicalReferenceType clone = this.cloneFactory.ShallowFieldClone(original); VerifyClone(original, clone, isDeepClone: false, isPropertyBasedClone: false); } @@ -113,7 +113,7 @@ namespace Nuclex.Support.Cloning { [Test] public void DeepFieldBasedClonesOfValueTypesCanBeMade() { HierarchicalValueType original = CreateValueType(); - HierarchicalValueType clone = this.cloneFactory.DeepClone(original, false); + HierarchicalValueType clone = this.cloneFactory.DeepFieldClone(original); VerifyClone(ref original, ref clone, isDeepClone: true, isPropertyBasedClone: false); } @@ -123,7 +123,7 @@ namespace Nuclex.Support.Cloning { [Test] public void DeepFieldBasedClonesOfReferenceTypesCanBeMade() { HierarchicalReferenceType original = CreateReferenceType(); - HierarchicalReferenceType clone = this.cloneFactory.DeepClone(original, false); + HierarchicalReferenceType clone = this.cloneFactory.DeepFieldClone(original); VerifyClone(original, clone, isDeepClone: true, isPropertyBasedClone: false); } @@ -133,7 +133,7 @@ namespace Nuclex.Support.Cloning { [Test] public void ShallowPropertyBasedClonesOfValueTypesCanBeMade() { HierarchicalValueType original = CreateValueType(); - HierarchicalValueType clone = this.cloneFactory.ShallowClone(original, true); + HierarchicalValueType clone = this.cloneFactory.ShallowPropertyClone(original); VerifyClone(ref original, ref clone, isDeepClone: false, isPropertyBasedClone: true); } @@ -143,7 +143,7 @@ namespace Nuclex.Support.Cloning { [Test] public void ShallowPropertyBasedClonesOfReferenceTypesCanBeMade() { HierarchicalReferenceType original = CreateReferenceType(); - HierarchicalReferenceType clone = this.cloneFactory.ShallowClone(original, true); + HierarchicalReferenceType clone = this.cloneFactory.ShallowPropertyClone(original); VerifyClone(original, clone, isDeepClone: false, isPropertyBasedClone: true); } @@ -153,7 +153,7 @@ namespace Nuclex.Support.Cloning { [Test] public void DeepPropertyBasedClonesOfValueTypesCanBeMade() { HierarchicalValueType original = CreateValueType(); - HierarchicalValueType clone = this.cloneFactory.DeepClone(original, true); + HierarchicalValueType clone = this.cloneFactory.DeepPropertyClone(original); VerifyClone(ref original, ref clone, isDeepClone: true, isPropertyBasedClone: true); } @@ -163,7 +163,7 @@ namespace Nuclex.Support.Cloning { [Test] public void DeepPropertyBasedClonesOfReferenceTypesCanBeMade() { HierarchicalReferenceType original = CreateReferenceType(); - HierarchicalReferenceType clone = this.cloneFactory.DeepClone(original, true); + HierarchicalReferenceType clone = this.cloneFactory.DeepPropertyClone(original); VerifyClone(original, clone, isDeepClone: true, isPropertyBasedClone: true); } diff --git a/Source/Cloning/ReflectionCloner.cs b/Source/Cloning/ReflectionCloner.cs index 869f13d..f845308 100644 --- a/Source/Cloning/ReflectionCloner.cs +++ b/Source/Cloning/ReflectionCloner.cs @@ -39,50 +39,17 @@ namespace Nuclex.Support.Cloning { /// /// Type of the object that will be cloned /// Object that will be cloned - /// - /// Whether to clone the object based on its properties only - /// /// A shallow clone of the provided object - public static TCloned ShallowClone( - TCloned objectToClone, bool usePropertyBasedClone - ) { + public static TCloned ShallowFieldClone(TCloned objectToClone) { Type originalType = objectToClone.GetType(); if(originalType.IsPrimitive || (originalType == typeof(string))) { return objectToClone; // Being value types, primitives are copied by default } else if(originalType.IsArray) { return (TCloned)shallowCloneArray(objectToClone); } else if(originalType.IsValueType) { - if(usePropertyBasedClone) { - return (TCloned)shallowCloneComplexPropertyBased(objectToClone); - } else { - return objectToClone; // Value types can be copied directly - } + return objectToClone; // Value types can be copied directly } else { - if(usePropertyBasedClone) { - return (TCloned)shallowCloneComplexPropertyBased(objectToClone); - } else { - return (TCloned)shallowCloneComplexFieldBased(objectToClone); - } - } - } - - /// - /// Creates a deep clone of the specified object, also creating clones of all - /// child objects being referenced - /// - /// Type of the object that will be cloned - /// Object that will be cloned - /// - /// Whether to clone the object based on its properties only - /// - /// A deep clone of the provided object - public static TCloned DeepClone( - TCloned objectToClone, bool usePropertyBasedClone - ) { - if(usePropertyBasedClone) { - return (TCloned)deepCloneSinglePropertyBased(objectToClone); - } else { - return (TCloned)deepCloneSingleFieldBased(objectToClone); + return (TCloned)shallowCloneComplexFieldBased(objectToClone); } } @@ -95,10 +62,17 @@ namespace Nuclex.Support.Cloning { /// Whether to clone the object based on its properties only /// /// A shallow clone of the provided object - TCloned ICloneFactory.ShallowClone( - TCloned objectToClone, bool usePropertyBasedClone - ) { - return ReflectionCloner.ShallowClone(objectToClone, usePropertyBasedClone); + public static TCloned ShallowPropertyClone(TCloned objectToClone) { + Type originalType = objectToClone.GetType(); + if(originalType.IsPrimitive || (originalType == typeof(string))) { + return objectToClone; // Being value types, primitives are copied by default + } else if(originalType.IsArray) { + return (TCloned)shallowCloneArray(objectToClone); + } else if(originalType.IsValueType) { + return (TCloned)shallowCloneComplexPropertyBased(objectToClone); + } else { + return (TCloned)shallowCloneComplexPropertyBased(objectToClone); + } } /// @@ -107,12 +81,62 @@ namespace Nuclex.Support.Cloning { /// /// Type of the object that will be cloned /// Object that will be cloned - /// - /// Whether to clone the object based on its properties only - /// /// A deep clone of the provided object - TCloned ICloneFactory.DeepClone(TCloned objectToClone, bool usePropertyBasedClone) { - return ReflectionCloner.DeepClone(objectToClone, usePropertyBasedClone); + public static TCloned DeepFieldClone(TCloned objectToClone) { + return (TCloned)deepCloneSingleFieldBased(objectToClone); + } + + /// + /// Creates a deep clone of the specified object, also creating clones of all + /// child objects being referenced + /// + /// Type of the object that will be cloned + /// Object that will be cloned + /// A deep clone of the provided object + public static TCloned DeepPropertyClone(TCloned objectToClone) { + return (TCloned)deepCloneSinglePropertyBased(objectToClone); + } + + /// + /// Creates a shallow clone of the specified object, reusing any referenced objects + /// + /// Type of the object that will be cloned + /// Object that will be cloned + /// A shallow clone of the provided object + TCloned ICloneFactory.ShallowFieldClone(TCloned objectToClone) { + return ReflectionCloner.ShallowFieldClone(objectToClone); + } + + /// + /// Creates a shallow clone of the specified object, reusing any referenced objects + /// + /// Type of the object that will be cloned + /// Object that will be cloned + /// A shallow clone of the provided object + TCloned ICloneFactory.ShallowPropertyClone(TCloned objectToClone) { + return ReflectionCloner.ShallowPropertyClone(objectToClone); + } + + /// + /// Creates a deep clone of the specified object, also creating clones of all + /// child objects being referenced + /// + /// Type of the object that will be cloned + /// Object that will be cloned + /// A deep clone of the provided object + TCloned ICloneFactory.DeepFieldClone(TCloned objectToClone) { + return ReflectionCloner.DeepFieldClone(objectToClone); + } + + /// + /// Creates a deep clone of the specified object, also creating clones of all + /// child objects being referenced + /// + /// Type of the object that will be cloned + /// Object that will be cloned + /// A deep clone of the provided object + TCloned ICloneFactory.DeepPropertyClone(TCloned objectToClone) { + return ReflectionCloner.DeepPropertyClone(objectToClone); } /// Clones a complex type using field-based value transfer diff --git a/Source/Cloning/SerializationCloner.Test.cs b/Source/Cloning/SerializationCloner.Test.cs index aa24f56..d550892 100644 --- a/Source/Cloning/SerializationCloner.Test.cs +++ b/Source/Cloning/SerializationCloner.Test.cs @@ -40,7 +40,7 @@ namespace Nuclex.Support.Cloning { [Test] public void PrimitiveTypesCanBeCloned() { int original = 12345; - int clone = this.cloneFactory.DeepClone(original, false); + int clone = this.cloneFactory.DeepFieldClone(original); Assert.AreEqual(original, clone); } @@ -50,7 +50,7 @@ namespace Nuclex.Support.Cloning { var original = new TestReferenceType[] { new TestReferenceType() { TestField = 123, TestProperty = 456 } }; - TestReferenceType[] clone = this.cloneFactory.DeepClone(original, false); + TestReferenceType[] clone = this.cloneFactory.DeepFieldClone(original); Assert.AreNotSame(original[0], clone[0]); Assert.AreEqual(original[0].TestField, clone[0].TestField); @@ -61,7 +61,7 @@ namespace Nuclex.Support.Cloning { [Test] public void GenericListsCanBeCloned() { var original = new List(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }); - List clone = this.cloneFactory.DeepClone(original, false); + List clone = this.cloneFactory.DeepFieldClone(original); CollectionAssert.AreEqual(original, clone); } @@ -71,7 +71,7 @@ namespace Nuclex.Support.Cloning { public void GenericDictionariesCanBeCloned() { var original = new Dictionary(); original.Add(1, "one"); - Dictionary clone = this.cloneFactory.DeepClone(original, false); + Dictionary clone = this.cloneFactory.DeepFieldClone(original); Assert.AreEqual("one", clone[1]); } @@ -82,7 +82,7 @@ namespace Nuclex.Support.Cloning { [Test] public void DeepFieldBasedClonesOfValueTypesCanBeMade() { HierarchicalValueType original = CreateValueType(); - HierarchicalValueType clone = this.cloneFactory.DeepClone(original, false); + HierarchicalValueType clone = this.cloneFactory.DeepFieldClone(original); VerifyClone(ref original, ref clone, isDeepClone: true, isPropertyBasedClone: false); } @@ -92,7 +92,7 @@ namespace Nuclex.Support.Cloning { [Test] public void DeepFieldBasedClonesOfReferenceTypesCanBeMade() { HierarchicalReferenceType original = CreateReferenceType(); - HierarchicalReferenceType clone = this.cloneFactory.DeepClone(original, false); + HierarchicalReferenceType clone = this.cloneFactory.DeepFieldClone(original); VerifyClone(original, clone, isDeepClone: true, isPropertyBasedClone: false); } @@ -102,7 +102,7 @@ namespace Nuclex.Support.Cloning { [Test] public void DeepPropertyBasedClonesOfValueTypesCanBeMade() { HierarchicalValueType original = CreateValueType(); - HierarchicalValueType clone = this.cloneFactory.DeepClone(original, true); + HierarchicalValueType clone = this.cloneFactory.DeepPropertyClone(original); VerifyClone(ref original, ref clone, isDeepClone: true, isPropertyBasedClone: true); } @@ -112,7 +112,7 @@ namespace Nuclex.Support.Cloning { [Test] public void DeepPropertyBasedClonesOfReferenceTypesCanBeMade() { HierarchicalReferenceType original = CreateReferenceType(); - HierarchicalReferenceType clone = this.cloneFactory.DeepClone(original, true); + HierarchicalReferenceType clone = this.cloneFactory.DeepPropertyClone(original); VerifyClone(original, clone, isDeepClone: true, isPropertyBasedClone: true); } diff --git a/Source/Cloning/SerializationCloner.cs b/Source/Cloning/SerializationCloner.cs index b14e02e..c1dddb4 100644 --- a/Source/Cloning/SerializationCloner.cs +++ b/Source/Cloning/SerializationCloner.cs @@ -242,23 +242,12 @@ namespace Nuclex.Support.Cloning { /// /// Type of the object that will be cloned /// Object that will be cloned - /// - /// Whether to clone the object based on its properties only - /// /// A deep clone of the provided object - public static TCloned DeepClone( - TCloned objectToClone, bool usePropertyBasedClone - ) { + public static TCloned DeepFieldClone(TCloned objectToClone) { using(var memoryStream = new MemoryStream()) { - if(usePropertyBasedClone) { - propertyBasedFormatter.Serialize(memoryStream, objectToClone); - memoryStream.Position = 0; - return (TCloned)propertyBasedFormatter.Deserialize(memoryStream); - } else { - fieldBasedFormatter.Serialize(memoryStream, objectToClone); - memoryStream.Position = 0; - return (TCloned)fieldBasedFormatter.Deserialize(memoryStream); - } + fieldBasedFormatter.Serialize(memoryStream, objectToClone); + memoryStream.Position = 0; + return (TCloned)fieldBasedFormatter.Deserialize(memoryStream); } } @@ -268,14 +257,13 @@ namespace Nuclex.Support.Cloning { /// /// Type of the object that will be cloned /// Object that will be cloned - /// - /// Whether to clone the object based on its properties only - /// /// A deep clone of the provided object - TCloned ICloneFactory.DeepClone( - TCloned objectToClone, bool usePropertyBasedClone - ) { - return SerializationCloner.DeepClone(objectToClone, usePropertyBasedClone); + public static TCloned DeepPropertyClone(TCloned objectToClone) { + using(var memoryStream = new MemoryStream()) { + propertyBasedFormatter.Serialize(memoryStream, objectToClone); + memoryStream.Position = 0; + return (TCloned)propertyBasedFormatter.Deserialize(memoryStream); + } } /// @@ -283,16 +271,43 @@ namespace Nuclex.Support.Cloning { /// /// Type of the object that will be cloned /// Object that will be cloned - /// - /// Whether to clone the object based on its properties only - /// /// A shallow clone of the provided object - TCloned ICloneFactory.ShallowClone( - TCloned objectToClone, bool usePropertyBasedClone - ) { + TCloned ICloneFactory.ShallowFieldClone(TCloned objectToClone) { throw new NotSupportedException("The serialization cloner cannot create shallow clones"); } + /// + /// Creates a shallow clone of the specified object, reusing any referenced objects + /// + /// Type of the object that will be cloned + /// Object that will be cloned + /// A shallow clone of the provided object + TCloned ICloneFactory.ShallowPropertyClone(TCloned objectToClone) { + throw new NotSupportedException("The serialization cloner cannot create shallow clones"); + } + + /// + /// Creates a deep clone of the specified object, also creating clones of all + /// child objects being referenced + /// + /// Type of the object that will be cloned + /// Object that will be cloned + /// A deep clone of the provided object + TCloned ICloneFactory.DeepFieldClone(TCloned objectToClone) { + return SerializationCloner.DeepFieldClone(objectToClone); + } + + /// + /// Creates a deep clone of the specified object, also creating clones of all + /// child objects being referenced + /// + /// Type of the object that will be cloned + /// Object that will be cloned + /// A deep clone of the provided object + TCloned ICloneFactory.DeepPropertyClone(TCloned objectToClone) { + return SerializationCloner.DeepPropertyClone(objectToClone); + } + /// Serializes objects by storing their fields private static BinaryFormatter fieldBasedFormatter; /// Serializes objects by storing their properties