From e7d1c9720b09d35345a94c17fa641692357f2aec Mon Sep 17 00:00:00 2001 From: Markus Ewald Date: Wed, 8 Feb 2012 11:12:44 +0000 Subject: [PATCH] Arrays of reference types can now be cloned, too - deep expression tree cloner is finished! git-svn-id: file:///srv/devel/repo-conversion/nusu@240 d2e56fa2-650e-0410-a79f-9358c0239efd --- Source/Cloning/ExpressionTreeCloner.Test.cs | 16 +++--- Source/Cloning/ExpressionTreeCloner.cs | 59 +++++++++------------ 2 files changed, 36 insertions(+), 39 deletions(-) diff --git a/Source/Cloning/ExpressionTreeCloner.Test.cs b/Source/Cloning/ExpressionTreeCloner.Test.cs index 8f782f3..9107a72 100644 --- a/Source/Cloning/ExpressionTreeCloner.Test.cs +++ b/Source/Cloning/ExpressionTreeCloner.Test.cs @@ -77,6 +77,7 @@ namespace Nuclex.Support.Cloning { Assert.AreSame(original[0], clone[0]); } #endif + /// Verifies that deep clones of arrays can be made [Test] public void DeepClonesOfArraysCanBeMade() { @@ -87,11 +88,11 @@ namespace Nuclex.Support.Cloning { }; TestReferenceType[,] clone = this.cloneFactory.DeepClone(original, false); - //Assert.AreNotSame(original[0, 0], clone[0, 0]); - //Assert.AreEqual(original[0,0].TestField, clone[0,0].TestField); - //Assert.AreEqual(original[0,0].TestProperty, clone[0,0].TestProperty); + Assert.AreNotSame(original[0, 0], clone[0, 0]); + Assert.AreEqual(original[0, 0].TestField, clone[0, 0].TestField); + Assert.AreEqual(original[0, 0].TestProperty, clone[0, 0].TestProperty); } -#if false + /// Verifies that deep clones of a generic list can be made [Test] public void GenericListsCanBeCloned() { @@ -111,6 +112,7 @@ namespace Nuclex.Support.Cloning { Assert.AreEqual("one", clone[1]); } +#if false /// /// Verifies that a field-based shallow clone of a value type can be performed /// @@ -138,7 +140,7 @@ namespace Nuclex.Support.Cloning { public void DeepFieldBasedClonesOfValueTypesCanBeMade() { HierarchicalValueType original = CreateValueType(); HierarchicalValueType clone = this.cloneFactory.DeepClone(original, false); - //VerifyClone(ref original, ref clone, isDeepClone: true, isPropertyBasedClone: false); + VerifyClone(ref original, ref clone, isDeepClone: true, isPropertyBasedClone: false); } /// @@ -148,7 +150,7 @@ namespace Nuclex.Support.Cloning { public void DeepFieldBasedClonesOfReferenceTypesCanBeMade() { HierarchicalReferenceType original = CreateReferenceType(); HierarchicalReferenceType clone = this.cloneFactory.DeepClone(original, false); - //VerifyClone(original, clone, isDeepClone: true, isPropertyBasedClone: false); + VerifyClone(original, clone, isDeepClone: true, isPropertyBasedClone: false); } #if false @@ -171,7 +173,9 @@ namespace Nuclex.Support.Cloning { HierarchicalReferenceType clone = this.cloneFactory.ShallowClone(original, true); VerifyClone(original, clone, isDeepClone: false, isPropertyBasedClone: true); } +#endif +#if false /// /// Verifies that a property-based deep clone of a value type can be performed /// diff --git a/Source/Cloning/ExpressionTreeCloner.cs b/Source/Cloning/ExpressionTreeCloner.cs index 158e7b1..7c960f4 100644 --- a/Source/Cloning/ExpressionTreeCloner.cs +++ b/Source/Cloning/ExpressionTreeCloner.cs @@ -285,23 +285,35 @@ namespace Nuclex.Support.Cloning { Expression.Assign(Expression.ArrayAccess(clone, indexes), clonedElement) ); } else { - ParameterExpression clonedElement = Expression.Variable(elementType); - loopVariables.Add(clonedElement); - - nestedTransferExpressions.Add( - Expression.Assign(clonedElement, originalElement) + // Complex types are cloned by checking their actual, concrete type (fields + // may be typed to an interface or base class) and requesting a cloner for that + // type during runtime + MethodInfo getOrCreateClonerMethodInfo = typeof(ExpressionTreeCloner).GetMethod( + "getOrCreateDeepFieldBasedCloner", + BindingFlags.NonPublic | BindingFlags.Static ); + MethodInfo getTypeMethodInfo = typeof(object).GetMethod("GetType"); + MethodInfo invokeMethodInfo = typeof(Func).GetMethod("Invoke"); - //generateComplexTypeTransferExpressions( - // elementType, - // originalElement, - // clonedElement, - // loopVariables, - // loopExpressions - //); - + // Generate expressions to do this: + // clone.SomeField = getOrCreateDeepFieldBasedCloner( + // original.SomeField.GetType() + // ).Invoke(original.SomeField); nestedTransferExpressions.Add( - Expression.Assign(Expression.ArrayAccess(clone, indexes), clonedElement) + Expression.Assign( + Expression.ArrayAccess(clone, indexes), + Expression.Convert( + Expression.Call( + Expression.Call( + getOrCreateClonerMethodInfo, + Expression.Call(originalElement, getTypeMethodInfo) + ), + invokeMethodInfo, + originalElement + ), + elementType + ) + ) ); } @@ -637,25 +649,6 @@ namespace Nuclex.Support.Cloning { throw new NotImplementedException(); } - /// - /// Compiles a method that copies the state of one object into another object - /// - /// Type of object whose state will be copied - /// Whether to create clones of the referenced objects - /// A method that copies the state from one object into another object - public static ReferenceAction CreateValueCopier(bool deepClone) - where TCloned : struct { - throw new NotImplementedException(); - } - - /// Compiles a method that creates a clone of an object - /// Type of object that will be cloned - /// Whether to create clones of the referenced objects - /// A method that clones an object of the provided type - public static Func CreateCloner(bool deepClone) - where TCloned : class, new() { - throw new NotImplementedException(); - } #endif /// Compiled cloners that perform shallow clone operations