From 7e61e2705065a6da06b4b339f7b9e661e534eb4d Mon Sep 17 00:00:00 2001 From: Markus Ewald Date: Thu, 2 Feb 2012 20:11:17 +0000 Subject: [PATCH] Reflection-based cloner no longer fails when cloning a complex type containing string members (since strings aren't primitive types, the cloner attempted to construct a string via its default constructor and then assign its members, which is nonsense) git-svn-id: file:///srv/devel/repo-conversion/nusu@226 d2e56fa2-650e-0410-a79f-9358c0239efd --- Source/Cloning/ReflectionCloner.Test.cs | 451 ++++++++++++++---------- Source/Cloning/ReflectionCloner.cs | 19 +- 2 files changed, 271 insertions(+), 199 deletions(-) diff --git a/Source/Cloning/ReflectionCloner.Test.cs b/Source/Cloning/ReflectionCloner.Test.cs index 71c118d..683171a 100644 --- a/Source/Cloning/ReflectionCloner.Test.cs +++ b/Source/Cloning/ReflectionCloner.Test.cs @@ -18,11 +18,11 @@ License along with this library */ #endregion -using System; -using System.IO; - #if UNITTEST +using System; +using System.Collections.Generic; + using NUnit.Framework; namespace Nuclex.Support.Cloning { @@ -111,6 +111,57 @@ namespace Nuclex.Support.Cloning { #endregion // struct HierarchicalReferenceType + /// Verifies that clones of primitive types can be created + [Test] + public void PrimitiveTypesCanBeCloned() { + int original = 12345; + int clone = (new ReflectionCloner()).ShallowClone(original, false); + Assert.AreEqual(original, clone); + } + + /// Verifies that shallow clones of arrays can be made + [Test] + public void ShallowClonesOfArraysCanBeMade() { + var original = new TestReferenceType[] { + new TestReferenceType() { TestField = 123, TestProperty = 456 } + }; + TestReferenceType[] clone = (new ReflectionCloner()).ShallowClone(original, false); + + Assert.AreSame(original[0], clone[0]); + } + + /// Verifies that deep clones of arrays can be made + [Test] + public void DeepClonesOfArraysCanBeMade() { + var original = new TestReferenceType[] { + new TestReferenceType() { TestField = 123, TestProperty = 456 } + }; + TestReferenceType[] clone = (new ReflectionCloner()).DeepClone(original, false); + + Assert.AreNotSame(original[0], clone[0]); + Assert.AreEqual(original[0].TestField, clone[0].TestField); + Assert.AreEqual(original[0].TestProperty, clone[0].TestProperty); + } + + /// Verifies that deep clones of a generic list can be made + [Test] + public void GenericListsCanBeCloned() { + var original = new List(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }); + List clone = (new ReflectionCloner()).DeepClone(original, false); + + CollectionAssert.AreEqual(original, clone); + } + + /// Verifies that deep clones of a generic dictionary can be made + [Test] + public void GenericDictionariesCanBeCloned() { + var original = new Dictionary(); + original.Add(1, "one"); + Dictionary clone = (new ReflectionCloner()).DeepClone(original, false); + + Assert.AreEqual("one", clone[1]); + } + /// /// Verifies that a field-based shallow clone of a value type can be performed /// @@ -118,7 +169,7 @@ namespace Nuclex.Support.Cloning { public void ShallowFieldBasedClonesOfValueTypesCanBeMade() { HierarchicalValueType original = createValueType(); HierarchicalValueType clone = (new ReflectionCloner()).ShallowClone(original, false); - verifyShallowFieldBasedValueTypeCopy(ref original, ref clone); + verifyClone(ref original, ref clone, isDeepClone: false, isPropertyBasedClone: false); } /// @@ -128,7 +179,7 @@ namespace Nuclex.Support.Cloning { public void ShallowFieldBasedClonesOfReferenceTypesCanBeMade() { HierarchicalReferenceType original = createReferenceType(); HierarchicalReferenceType clone = (new ReflectionCloner()).ShallowClone(original, false); - verifyShallowFieldBasedReferenceTypeCopy(original, clone); + verifyClone(original, clone, isDeepClone: false, isPropertyBasedClone: false); } /// @@ -138,7 +189,7 @@ namespace Nuclex.Support.Cloning { public void DeepFieldBasedClonesOfValueTypesCanBeMade() { HierarchicalValueType original = createValueType(); HierarchicalValueType clone = (new ReflectionCloner()).DeepClone(original, false); - verifyDeepFieldBasedValueTypeCopy(ref original, ref clone); + verifyClone(ref original, ref clone, isDeepClone: true, isPropertyBasedClone: false); } /// @@ -148,7 +199,7 @@ namespace Nuclex.Support.Cloning { public void DeepFieldBasedClonesOfReferenceTypesCanBeMade() { HierarchicalReferenceType original = createReferenceType(); HierarchicalReferenceType clone = (new ReflectionCloner()).DeepClone(original, false); - verifyDeepFieldBasedReferenceTypeCopy(ref original, ref clone); + verifyClone(original, clone, isDeepClone: true, isPropertyBasedClone: false); } /// @@ -158,7 +209,7 @@ namespace Nuclex.Support.Cloning { public void ShallowPropertyBasedClonesOfValueTypesCanBeMade() { HierarchicalValueType original = createValueType(); HierarchicalValueType clone = (new ReflectionCloner()).ShallowClone(original, true); - verifyShallowPropertyBasedValueTypeCopy(ref original, ref clone); + verifyClone(ref original, ref clone, isDeepClone: false, isPropertyBasedClone: true); } /// @@ -168,7 +219,7 @@ namespace Nuclex.Support.Cloning { public void ShallowPropertyBasedClonesOfReferenceTypesCanBeMade() { HierarchicalReferenceType original = createReferenceType(); HierarchicalReferenceType clone = (new ReflectionCloner()).ShallowClone(original, true); - verifyShallowPropertyBasedReferenceTypeCopy(ref original, ref clone); + verifyClone(original, clone, isDeepClone: false, isPropertyBasedClone: true); } /// @@ -178,7 +229,7 @@ namespace Nuclex.Support.Cloning { public void DeepPropertyBasedClonesOfValueTypesCanBeMade() { HierarchicalValueType original = createValueType(); HierarchicalValueType clone = (new ReflectionCloner()).DeepClone(original, true); - verifyDeepPropertyBasedValueTypeCopy(ref original, ref clone); + verifyClone(ref original, ref clone, isDeepClone: true, isPropertyBasedClone: true); } /// @@ -188,217 +239,235 @@ namespace Nuclex.Support.Cloning { public void DeepPropertyBasedClonesOfReferenceTypesCanBeMade() { HierarchicalReferenceType original = createReferenceType(); HierarchicalReferenceType clone = (new ReflectionCloner()).DeepClone(original, true); - verifyDeepPropertyBasedReferenceTypeCopy(ref original, ref clone); + verifyClone(original, clone, isDeepClone: true, isPropertyBasedClone: true); } /// - /// Verifies that a field-based shallow clone of a value type matches - /// the expected outcome for this type of clone + /// Verifies that a cloned object exhibits the expected state for the type of + /// clone that has been performed /// - /// Original instance that has been cloned - /// Cloned instance that will be verified - private static void verifyShallowFieldBasedValueTypeCopy( - ref HierarchicalValueType original, ref HierarchicalValueType clone + /// Original instance the clone was created from + /// Cloned instance that will be checked for correctness + /// Whether the cloned instance is a deep clone + /// + /// Whether a property-based clone was performed + /// + private static void verifyClone( + HierarchicalReferenceType original, HierarchicalReferenceType clone, + bool isDeepClone, bool isPropertyBasedClone ) { - Assert.AreEqual(original.TestField, clone.TestField); - Assert.AreEqual(original.TestProperty, clone.TestProperty); - Assert.AreEqual(original.ValueTypeField.TestField, clone.ValueTypeField.TestField); - Assert.AreEqual(original.ValueTypeField.TestProperty, clone.ValueTypeField.TestProperty); - Assert.AreEqual( - original.ValueTypeProperty.TestField, clone.ValueTypeProperty.TestField - ); - Assert.AreEqual( - original.ValueTypeProperty.TestProperty, clone.ValueTypeProperty.TestProperty - ); - Assert.AreSame(original.ReferenceTypeField, clone.ReferenceTypeField); - Assert.AreSame(original.ReferenceTypeProperty, clone.ReferenceTypeProperty); - } + if(isPropertyBasedClone) { + Assert.AreEqual(0, clone.TestField); + Assert.AreEqual(0, clone.ValueTypeField.TestField); + Assert.AreEqual(0, clone.ValueTypeField.TestProperty); + Assert.AreEqual(0, clone.ValueTypeProperty.TestField); + Assert.IsNull(clone.ReferenceTypeField); - /// - /// Verifies that a field-based shallow clone of a reference type matches - /// the expected outcome for this type of clone - /// - /// Original instance that has been cloned - /// Cloned instance that will be verified - private static void verifyShallowFieldBasedReferenceTypeCopy( - HierarchicalReferenceType original, HierarchicalReferenceType clone - ) { - Assert.AreEqual(original.TestField, clone.TestField); - Assert.AreEqual(original.TestProperty, clone.TestProperty); - Assert.AreEqual(original.ValueTypeField.TestField, clone.ValueTypeField.TestField); - Assert.AreEqual(original.ValueTypeField.TestProperty, clone.ValueTypeField.TestProperty); - Assert.AreEqual( - original.ValueTypeProperty.TestField, clone.ValueTypeProperty.TestField - ); - Assert.AreEqual( - original.ValueTypeProperty.TestProperty, clone.ValueTypeProperty.TestProperty - ); - Assert.AreSame(original.ReferenceTypeField, clone.ReferenceTypeField); - Assert.AreSame(original.ReferenceTypeProperty, clone.ReferenceTypeProperty); - } + if(isDeepClone) { + Assert.AreNotSame(original.ReferenceTypeProperty, clone.ReferenceTypeProperty); + Assert.AreNotSame( + original.ReferenceTypeArrayProperty, clone.ReferenceTypeArrayProperty + ); + Assert.AreEqual(0, clone.ReferenceTypeProperty.TestField); + Assert.AreNotSame( + original.ReferenceTypeArrayProperty[1, 3][0], + clone.ReferenceTypeArrayProperty[1, 3][0] + ); + Assert.AreNotSame( + original.ReferenceTypeArrayProperty[1, 3][2], + clone.ReferenceTypeArrayProperty[1, 3][2] + ); + Assert.AreEqual(0, clone.ReferenceTypeArrayProperty[1, 3][0].TestField); + Assert.AreEqual(0, clone.ReferenceTypeArrayProperty[1, 3][2].TestField); + } else { + Assert.AreSame(original.ReferenceTypeProperty, clone.ReferenceTypeProperty); + Assert.AreSame( + original.ReferenceTypeArrayProperty, clone.ReferenceTypeArrayProperty + ); + } + } else { + Assert.AreEqual(original.TestField, clone.TestField); + Assert.AreEqual(original.ValueTypeField.TestField, clone.ValueTypeField.TestField); + Assert.AreEqual(original.ValueTypeField.TestProperty, clone.ValueTypeField.TestProperty); + Assert.AreEqual( + original.ValueTypeProperty.TestField, clone.ValueTypeProperty.TestField + ); + Assert.AreEqual( + original.ReferenceTypeField.TestField, clone.ReferenceTypeField.TestField + ); + Assert.AreEqual( + original.ReferenceTypeField.TestProperty, clone.ReferenceTypeField.TestProperty + ); + Assert.AreEqual( + original.ReferenceTypeProperty.TestField, clone.ReferenceTypeProperty.TestField + ); + + if(isDeepClone) { + Assert.AreNotSame(original.ReferenceTypeField, clone.ReferenceTypeField); + Assert.AreNotSame(original.ReferenceTypeProperty, clone.ReferenceTypeProperty); + Assert.AreNotSame( + original.ReferenceTypeArrayField, clone.ReferenceTypeArrayField + ); + Assert.AreNotSame( + original.ReferenceTypeArrayProperty, clone.ReferenceTypeArrayProperty + ); + Assert.AreNotSame( + original.ReferenceTypeArrayProperty[1, 3][0], + clone.ReferenceTypeArrayProperty[1, 3][0] + ); + Assert.AreNotSame( + original.ReferenceTypeArrayProperty[1, 3][2], + clone.ReferenceTypeArrayProperty[1, 3][2] + ); + Assert.AreEqual( + original.ReferenceTypeArrayProperty[1, 3][0].TestField, + clone.ReferenceTypeArrayProperty[1, 3][0].TestField + ); + Assert.AreEqual( + original.ReferenceTypeArrayProperty[1, 3][2].TestField, + clone.ReferenceTypeArrayProperty[1, 3][2].TestField + ); + } else { + Assert.AreSame(original.ReferenceTypeField, clone.ReferenceTypeField); + Assert.AreSame(original.ReferenceTypeProperty, clone.ReferenceTypeProperty); + Assert.AreSame( + original.ReferenceTypeArrayField, clone.ReferenceTypeArrayField + ); + Assert.AreSame( + original.ReferenceTypeArrayProperty, clone.ReferenceTypeArrayProperty + ); + } + } - /// - /// Verifies that a field-based deep clone of a value type matches - /// the expected outcome for this type of clone - /// - /// Original instance that has been cloned - /// Cloned instance that will be verified - private static void verifyDeepFieldBasedValueTypeCopy( - ref HierarchicalValueType original, ref HierarchicalValueType clone - ) { - Assert.AreEqual(original.TestField, clone.TestField); Assert.AreEqual(original.TestProperty, clone.TestProperty); - Assert.AreEqual(original.ValueTypeField.TestField, clone.ValueTypeField.TestField); - Assert.AreEqual(original.ValueTypeField.TestProperty, clone.ValueTypeField.TestProperty); - Assert.AreEqual( - original.ValueTypeProperty.TestField, clone.ValueTypeProperty.TestField - ); Assert.AreEqual( original.ValueTypeProperty.TestProperty, clone.ValueTypeProperty.TestProperty ); - Assert.AreEqual( - original.ReferenceTypeField.TestField, clone.ReferenceTypeField.TestField - ); - Assert.AreEqual( - original.ReferenceTypeField.TestProperty, clone.ReferenceTypeField.TestProperty - ); - Assert.AreEqual( - original.ReferenceTypeProperty.TestField, clone.ReferenceTypeProperty.TestField - ); Assert.AreEqual( original.ReferenceTypeProperty.TestProperty, clone.ReferenceTypeProperty.TestProperty ); - Assert.AreNotSame(original.ReferenceTypeField, clone.ReferenceTypeField); - Assert.AreNotSame(original.ReferenceTypeProperty, clone.ReferenceTypeProperty); + Assert.AreEqual( + original.ReferenceTypeArrayProperty[1, 3][0].TestProperty, + clone.ReferenceTypeArrayProperty[1, 3][0].TestProperty + ); + Assert.AreEqual( + original.ReferenceTypeArrayProperty[1, 3][2].TestProperty, + clone.ReferenceTypeArrayProperty[1, 3][2].TestProperty + ); } /// - /// Verifies that a field-based deep clone of a reference type matches - /// the expected outcome for this type of clone + /// Verifies that a cloned object exhibits the expected state for the type of + /// clone that has been performed /// - /// Original instance that has been cloned - /// Cloned instance that will be verified - private static void verifyDeepFieldBasedReferenceTypeCopy( - ref HierarchicalReferenceType original, ref HierarchicalReferenceType clone + /// Original instance the clone was created from + /// Cloned instance that will be checked for correctness + /// Whether the cloned instance is a deep clone + /// + /// Whether a property-based clone was performed + /// + private static void verifyClone( + ref HierarchicalValueType original, ref HierarchicalValueType clone, + bool isDeepClone, bool isPropertyBasedClone ) { - Assert.AreEqual(original.TestField, clone.TestField); + if(isPropertyBasedClone) { + Assert.AreEqual(0, clone.TestField); + Assert.AreEqual(0, clone.ValueTypeField.TestField); + Assert.AreEqual(0, clone.ValueTypeField.TestProperty); + Assert.AreEqual(0, clone.ValueTypeProperty.TestField); + Assert.IsNull(clone.ReferenceTypeField); + + if(isDeepClone) { + Assert.AreNotSame(original.ReferenceTypeProperty, clone.ReferenceTypeProperty); + Assert.AreNotSame( + original.ReferenceTypeArrayProperty, clone.ReferenceTypeArrayProperty + ); + Assert.AreEqual(0, clone.ReferenceTypeProperty.TestField); + Assert.AreNotSame( + original.ReferenceTypeArrayProperty[1, 3][0], + clone.ReferenceTypeArrayProperty[1, 3][0] + ); + Assert.AreNotSame( + original.ReferenceTypeArrayProperty[1, 3][2], + clone.ReferenceTypeArrayProperty[1, 3][2] + ); + Assert.AreEqual(0, clone.ReferenceTypeArrayProperty[1, 3][0].TestField); + Assert.AreEqual(0, clone.ReferenceTypeArrayProperty[1, 3][2].TestField); + } else { + Assert.AreSame(original.ReferenceTypeProperty, clone.ReferenceTypeProperty); + Assert.AreSame( + original.ReferenceTypeArrayProperty, clone.ReferenceTypeArrayProperty + ); + } + } else { + Assert.AreEqual(original.TestField, clone.TestField); + Assert.AreEqual(original.ValueTypeField.TestField, clone.ValueTypeField.TestField); + Assert.AreEqual(original.ValueTypeField.TestProperty, clone.ValueTypeField.TestProperty); + Assert.AreEqual( + original.ValueTypeProperty.TestField, clone.ValueTypeProperty.TestField + ); + Assert.AreEqual( + original.ReferenceTypeField.TestField, clone.ReferenceTypeField.TestField + ); + Assert.AreEqual( + original.ReferenceTypeField.TestProperty, clone.ReferenceTypeField.TestProperty + ); + Assert.AreEqual( + original.ReferenceTypeProperty.TestField, clone.ReferenceTypeProperty.TestField + ); + + if(isDeepClone) { + Assert.AreNotSame(original.ReferenceTypeField, clone.ReferenceTypeField); + Assert.AreNotSame(original.ReferenceTypeProperty, clone.ReferenceTypeProperty); + Assert.AreNotSame( + original.ReferenceTypeArrayField, clone.ReferenceTypeArrayField + ); + Assert.AreNotSame( + original.ReferenceTypeArrayProperty, clone.ReferenceTypeArrayProperty + ); + Assert.AreNotSame( + original.ReferenceTypeArrayProperty[1, 3][0], + clone.ReferenceTypeArrayProperty[1, 3][0] + ); + Assert.AreNotSame( + original.ReferenceTypeArrayProperty[1, 3][2], + clone.ReferenceTypeArrayProperty[1, 3][2] + ); + Assert.AreEqual( + original.ReferenceTypeArrayProperty[1, 3][0].TestField, + clone.ReferenceTypeArrayProperty[1, 3][0].TestField + ); + Assert.AreEqual( + original.ReferenceTypeArrayProperty[1, 3][2].TestField, + clone.ReferenceTypeArrayProperty[1, 3][2].TestField + ); + } else { + Assert.AreSame(original.ReferenceTypeField, clone.ReferenceTypeField); + Assert.AreSame(original.ReferenceTypeProperty, clone.ReferenceTypeProperty); + Assert.AreSame( + original.ReferenceTypeArrayField, clone.ReferenceTypeArrayField + ); + Assert.AreSame( + original.ReferenceTypeArrayProperty, clone.ReferenceTypeArrayProperty + ); + } + } + Assert.AreEqual(original.TestProperty, clone.TestProperty); - Assert.AreEqual(original.ValueTypeField.TestField, clone.ValueTypeField.TestField); - Assert.AreEqual(original.ValueTypeField.TestProperty, clone.ValueTypeField.TestProperty); - Assert.AreEqual( - original.ValueTypeProperty.TestField, clone.ValueTypeProperty.TestField - ); Assert.AreEqual( original.ValueTypeProperty.TestProperty, clone.ValueTypeProperty.TestProperty ); - Assert.AreEqual( - original.ReferenceTypeField.TestField, clone.ReferenceTypeField.TestField - ); - Assert.AreEqual( - original.ReferenceTypeField.TestProperty, clone.ReferenceTypeField.TestProperty - ); - Assert.AreEqual( - original.ReferenceTypeProperty.TestField, clone.ReferenceTypeProperty.TestField - ); Assert.AreEqual( original.ReferenceTypeProperty.TestProperty, clone.ReferenceTypeProperty.TestProperty ); - Assert.AreNotSame(original.ReferenceTypeField, clone.ReferenceTypeField); - Assert.AreNotSame(original.ReferenceTypeProperty, clone.ReferenceTypeProperty); - } - - /// - /// Verifies that a property-based shallow clone of a value type matches - /// the expected outcome for this type of clone - /// - /// Original instance that has been cloned - /// Cloned instance that will be verified - private static void verifyShallowPropertyBasedValueTypeCopy( - ref HierarchicalValueType original, ref HierarchicalValueType clone - ) { - Assert.AreEqual(0, clone.TestField); - Assert.AreEqual(original.TestProperty, clone.TestProperty); - Assert.AreEqual(0, clone.ValueTypeField.TestField); - Assert.AreEqual(0, clone.ValueTypeField.TestProperty); - Assert.AreEqual(0, clone.ValueTypeProperty.TestField); Assert.AreEqual( - original.ValueTypeProperty.TestProperty, clone.ValueTypeProperty.TestProperty + original.ReferenceTypeArrayProperty[1, 3][0].TestProperty, + clone.ReferenceTypeArrayProperty[1, 3][0].TestProperty ); - Assert.IsNull(clone.ReferenceTypeField); - Assert.AreSame(original.ReferenceTypeProperty, clone.ReferenceTypeProperty); - } - - /// - /// Verifies that a property-based shallow clone of a reference type matches - /// the expected outcome for this type of clone - /// - /// Original instance that has been cloned - /// Cloned instance that will be verified - private static void verifyShallowPropertyBasedReferenceTypeCopy( - ref HierarchicalReferenceType original, ref HierarchicalReferenceType clone - ) { - Assert.AreEqual(0, clone.TestField); - Assert.AreEqual(original.TestProperty, clone.TestProperty); - Assert.AreEqual(0, clone.ValueTypeField.TestField); - Assert.AreEqual(0, clone.ValueTypeField.TestProperty); - Assert.AreEqual(0, clone.ValueTypeProperty.TestField); Assert.AreEqual( - original.ValueTypeProperty.TestProperty, clone.ValueTypeProperty.TestProperty + original.ReferenceTypeArrayProperty[1, 3][2].TestProperty, + clone.ReferenceTypeArrayProperty[1, 3][2].TestProperty ); - Assert.IsNull(clone.ReferenceTypeField); - Assert.AreSame(original.ReferenceTypeProperty, clone.ReferenceTypeProperty); - } - - /// - /// Verifies that a property-based deep clone of a value type matches - /// the expected outcome for this type of clone - /// - /// Original instance that has been cloned - /// Cloned instance that will be verified - private static void verifyDeepPropertyBasedValueTypeCopy( - ref HierarchicalValueType original, ref HierarchicalValueType clone - ) { - Assert.AreEqual(0, clone.TestField); - Assert.AreEqual(original.TestProperty, clone.TestProperty); - Assert.AreEqual(0, clone.ValueTypeField.TestField); - Assert.AreEqual(0, clone.ValueTypeField.TestProperty); - Assert.AreEqual(0, clone.ValueTypeProperty.TestField); - Assert.AreEqual( - original.ValueTypeProperty.TestProperty, clone.ValueTypeProperty.TestProperty - ); - Assert.IsNull(clone.ReferenceTypeField); - Assert.AreEqual(0, clone.ReferenceTypeProperty.TestField); - Assert.AreEqual( - original.ReferenceTypeProperty.TestProperty, clone.ReferenceTypeProperty.TestProperty - ); - Assert.IsNull(clone.ReferenceTypeField); - Assert.AreNotSame(original.ReferenceTypeProperty, clone.ReferenceTypeProperty); - } - - /// - /// Verifies that a property-based deep clone of a reference type matches - /// the expected outcome for this type of clone - /// - /// Original instance that has been cloned - /// Cloned instance that will be verified - private static void verifyDeepPropertyBasedReferenceTypeCopy( - ref HierarchicalReferenceType original, ref HierarchicalReferenceType clone - ) { - Assert.AreEqual(0, clone.TestField); - Assert.AreEqual(original.TestProperty, clone.TestProperty); - Assert.AreEqual(0, clone.ValueTypeField.TestField); - Assert.AreEqual(0, clone.ValueTypeField.TestProperty); - Assert.AreEqual(0, clone.ValueTypeProperty.TestField); - Assert.AreEqual( - original.ValueTypeProperty.TestProperty, clone.ValueTypeProperty.TestProperty - ); - Assert.IsNull(clone.ReferenceTypeField); - Assert.AreEqual(0, clone.ReferenceTypeProperty.TestField); - Assert.AreEqual( - original.ReferenceTypeProperty.TestProperty, clone.ReferenceTypeProperty.TestProperty - ); - Assert.IsNull(clone.ReferenceTypeField); - Assert.AreNotSame(original.ReferenceTypeProperty, clone.ReferenceTypeProperty); } /// Creates a value type with random data for testing diff --git a/Source/Cloning/ReflectionCloner.cs b/Source/Cloning/ReflectionCloner.cs index 91e92e6..357d49c 100644 --- a/Source/Cloning/ReflectionCloner.cs +++ b/Source/Cloning/ReflectionCloner.cs @@ -37,7 +37,7 @@ namespace Nuclex.Support.Cloning { /// A shallow clone of the provided object public TCloned ShallowClone(TCloned objectToClone, bool usePropertyBasedClone) { Type originalType = objectToClone.GetType(); - if(originalType.IsPrimitive) { + if(originalType.IsPrimitive || (originalType == typeof(string))) { return objectToClone; // Being value types, primitives are copied by default } else if(originalType.IsArray) { return (TCloned)shallowCloneArray(objectToClone); @@ -113,7 +113,8 @@ namespace Nuclex.Support.Cloning { Type propertyType = propertyInfo.PropertyType; object originalValue = propertyInfo.GetValue(original, null); if(originalValue != null) { - if(propertyType.IsPrimitive) { // Primitive types can be assigned directly + if(propertyType.IsPrimitive || (propertyType == typeof(string))) { + // Primitive types can be assigned directly propertyInfo.SetValue(clone, originalValue, null); } else if(propertyType.IsValueType) { // Value types are seen as part of the original type and are thus recursed into @@ -141,7 +142,7 @@ namespace Nuclex.Support.Cloning { /// A clone of the original object private static object deepCloneSingleFieldBased(object original) { Type originalType = original.GetType(); - if(originalType.IsPrimitive) { + if(originalType.IsPrimitive || (originalType == typeof(string))) { return original; // Creates another box, does not reference boxed primitive } else if(originalType.IsArray) { return deepCloneArrayFieldBased((Array)original, originalType.GetElementType()); @@ -166,7 +167,8 @@ namespace Nuclex.Support.Cloning { Type fieldType = fieldInfo.FieldType; object originalValue = fieldInfo.GetValue(original); if(originalValue != null) { - if(fieldType.IsPrimitive) { // Primitive types can be assigned directly + // Primitive types can be assigned directly + if(fieldType.IsPrimitive || (fieldType == typeof(string))) { fieldInfo.SetValue(clone, originalValue); } else if(fieldType.IsArray) { // Arrays need to be cloned element-by-element fieldInfo.SetValue( @@ -187,7 +189,7 @@ namespace Nuclex.Support.Cloning { /// Type of elements the original array contains /// A clone of the original array private static object deepCloneArrayFieldBased(Array original, Type elementType) { - if(elementType.IsPrimitive) { + if(elementType.IsPrimitive || (elementType == typeof(string))) { return original.Clone(); } @@ -252,7 +254,7 @@ namespace Nuclex.Support.Cloning { /// A clone of the original object private static object deepCloneSinglePropertyBased(object original) { Type originalType = original.GetType(); - if(originalType.IsPrimitive) { + if(originalType.IsPrimitive || (originalType == typeof(string))) { return original; // Creates another box, does not reference boxed primitive } else if(originalType.IsArray) { return deepCloneArrayPropertyBased((Array)original, originalType.GetElementType()); @@ -277,7 +279,8 @@ namespace Nuclex.Support.Cloning { Type propertyType = propertyInfo.PropertyType; object originalValue = propertyInfo.GetValue(original, null); if(originalValue != null) { - if(propertyType.IsPrimitive) { // Primitive types can be assigned directly + if(propertyType.IsPrimitive || (propertyType == typeof(string))) { + // Primitive types can be assigned directly propertyInfo.SetValue(clone, originalValue, null); } else if(propertyType.IsArray) { // Arrays need to be cloned element-by-element propertyInfo.SetValue( @@ -299,7 +302,7 @@ namespace Nuclex.Support.Cloning { /// Type of elements the original array contains /// A clone of the original array private static object deepCloneArrayPropertyBased(Array original, Type elementType) { - if(elementType.IsPrimitive) { + if(elementType.IsPrimitive || (elementType == typeof(string))) { return original.Clone(); }