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
This commit is contained in:
Markus Ewald 2012-02-08 17:13:08 +00:00
parent 0f2bb60ea5
commit 15300676ba
7 changed files with 277 additions and 177 deletions

View File

@ -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<int>(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 });
List<int> clone = this.cloneFactory.DeepClone(original, false);
List<int> clone = this.cloneFactory.DeepFieldClone(original);
CollectionAssert.AreEqual(original, clone);
}
@ -105,7 +105,7 @@ namespace Nuclex.Support.Cloning {
public void GenericDictionariesCanBeCloned() {
var original = new Dictionary<int, string>();
original.Add(1, "one");
Dictionary<int, string> clone = this.cloneFactory.DeepClone(original, false);
Dictionary<int, string> 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);
}

View File

@ -45,66 +45,32 @@ namespace Nuclex.Support.Cloning {
/// </summary>
/// <typeparam name="TCloned">Type of the object that will be cloned</typeparam>
/// <param name="objectToClone">Object that will be cloned</param>
/// <param name="usePropertyBasedClone">
/// Whether to clone the object based on its properties only
/// </param>
/// <returns>A deep clone of the provided object</returns>
public static TCloned DeepClone<TCloned>(
TCloned objectToClone, bool usePropertyBasedClone
) {
public static TCloned DeepFieldClone<TCloned>(TCloned objectToClone) {
object objectToCloneAsObject = objectToClone;
if(objectToCloneAsObject == null) {
return default(TCloned);
}
Func<object, object> cloner;
if(usePropertyBasedClone) {
cloner = getOrCreateDeepPropertyBasedCloner(typeof(TCloned));
} else {
cloner = getOrCreateDeepFieldBasedCloner(typeof(TCloned));
}
Func<object, object> cloner = getOrCreateDeepFieldBasedCloner(typeof(TCloned));
return (TCloned)cloner(objectToCloneAsObject);
}
/// <summary>
/// Creates a shallow clone of the specified object, reusing any referenced objects
/// </summary>
/// <typeparam name="TCloned">Type of the object that will be cloned</typeparam>
/// <param name="objectToClone">Object that will be cloned</param>
/// <param name="usePropertyBasedClone">
/// Whether to clone the object based on its properties only
/// </param>
/// <returns>A shallow clone of the provided object</returns>
public static TCloned ShallowClone<TCloned>(
TCloned objectToClone, bool usePropertyBasedClone
) {
object objectToCloneAsObject = objectToClone;
if(objectToCloneAsObject == null) {
return default(TCloned);
}
if(usePropertyBasedClone) {
throw new NotImplementedException("Not implemented yet");
} else {
Func<object, object> cloner = getOrCreateShallowFieldBasedCloner(typeof(TCloned));
return (TCloned)cloner(objectToCloneAsObject);
}
}
/// <summary>
/// Creates a deep clone of the specified object, also creating clones of all
/// child objects being referenced
/// </summary>
/// <typeparam name="TCloned">Type of the object that will be cloned</typeparam>
/// <param name="objectToClone">Object that will be cloned</param>
/// <param name="usePropertyBasedClone">
/// Whether to clone the object based on its properties only
/// </param>
/// <returns>A deep clone of the provided object</returns>
TCloned ICloneFactory.DeepClone<TCloned>(
TCloned objectToClone, bool usePropertyBasedClone
) {
return ExpressionTreeCloner.DeepClone<TCloned>(objectToClone, usePropertyBasedClone);
public static TCloned DeepPropertyClone<TCloned>(TCloned objectToClone) {
object objectToCloneAsObject = objectToClone;
if(objectToCloneAsObject == null) {
return default(TCloned);
}
Func<object, object> cloner = getOrCreateDeepPropertyBasedCloner(typeof(TCloned));
return (TCloned)cloner(objectToCloneAsObject);
}
/// <summary>
@ -112,14 +78,74 @@ namespace Nuclex.Support.Cloning {
/// </summary>
/// <typeparam name="TCloned">Type of the object that will be cloned</typeparam>
/// <param name="objectToClone">Object that will be cloned</param>
/// <param name="usePropertyBasedClone">
/// Whether to clone the object based on its properties only
/// </param>
/// <returns>A shallow clone of the provided object</returns>
TCloned ICloneFactory.ShallowClone<TCloned>(
TCloned objectToClone, bool usePropertyBasedClone
) {
return ExpressionTreeCloner.ShallowClone<TCloned>(objectToClone, usePropertyBasedClone);
public static TCloned ShallowFieldClone<TCloned>(TCloned objectToClone) {
object objectToCloneAsObject = objectToClone;
if(objectToCloneAsObject == null) {
return default(TCloned);
}
Func<object, object> cloner = getOrCreateShallowFieldBasedCloner(typeof(TCloned));
return (TCloned)cloner(objectToCloneAsObject);
}
/// <summary>
/// Creates a shallow clone of the specified object, reusing any referenced objects
/// </summary>
/// <typeparam name="TCloned">Type of the object that will be cloned</typeparam>
/// <param name="objectToClone">Object that will be cloned</param>
/// <returns>A shallow clone of the provided object</returns>
public static TCloned ShallowPropertyClone<TCloned>(TCloned objectToClone) {
object objectToCloneAsObject = objectToClone;
if(objectToCloneAsObject == null) {
return default(TCloned);
}
throw new NotImplementedException("Not implemented yet");
Func<object, object> cloner = getOrCreateShallowFieldBasedCloner(typeof(TCloned));
return (TCloned)cloner(objectToCloneAsObject);
}
/// <summary>
/// Creates a shallow clone of the specified object, reusing any referenced objects
/// </summary>
/// <typeparam name="TCloned">Type of the object that will be cloned</typeparam>
/// <param name="objectToClone">Object that will be cloned</param>
/// <returns>A shallow clone of the provided object</returns>
TCloned ICloneFactory.ShallowFieldClone<TCloned>(TCloned objectToClone) {
return ExpressionTreeCloner.ShallowFieldClone<TCloned>(objectToClone);
}
/// <summary>
/// Creates a shallow clone of the specified object, reusing any referenced objects
/// </summary>
/// <typeparam name="TCloned">Type of the object that will be cloned</typeparam>
/// <param name="objectToClone">Object that will be cloned</param>
/// <returns>A shallow clone of the provided object</returns>
TCloned ICloneFactory.ShallowPropertyClone<TCloned>(TCloned objectToClone) {
return ExpressionTreeCloner.ShallowPropertyClone<TCloned>(objectToClone);
}
/// <summary>
/// Creates a deep clone of the specified object, also creating clones of all
/// child objects being referenced
/// </summary>
/// <typeparam name="TCloned">Type of the object that will be cloned</typeparam>
/// <param name="objectToClone">Object that will be cloned</param>
/// <returns>A deep clone of the provided object</returns>
TCloned ICloneFactory.DeepFieldClone<TCloned>(TCloned objectToClone) {
return ExpressionTreeCloner.DeepFieldClone<TCloned>(objectToClone);
}
/// <summary>
/// Creates a deep clone of the specified object, also creating clones of all
/// child objects being referenced
/// </summary>
/// <typeparam name="TCloned">Type of the object that will be cloned</typeparam>
/// <param name="objectToClone">Object that will be cloned</param>
/// <returns>A deep clone of the provided object</returns>
TCloned ICloneFactory.DeepPropertyClone<TCloned>(TCloned objectToClone) {
return ExpressionTreeCloner.DeepPropertyClone<TCloned>(objectToClone);
}
#if false

View File

@ -26,39 +26,74 @@ namespace Nuclex.Support.Cloning {
public interface ICloneFactory {
/// <summary>
/// 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
/// </summary>
/// <typeparam name="TCloned">Type of the object that will be cloned</typeparam>
/// <param name="objectToClone">Object that will be cloned</param>
/// <param name="usePropertyBasedClone">
/// Whether to clone the object based on its properties only
/// </param>
/// <returns>A deep clone of the provided object</returns>
/// <returns>A shallow clone of the provided object</returns>
/// <remarks>
/// 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.
/// </remarks>
TCloned DeepClone<TCloned>(TCloned objectToClone, bool usePropertyBasedClone);
TCloned ShallowFieldClone<TCloned>(TCloned objectToClone);
/// <summary>
/// Creates a shallow clone of the specified object, reusing any referenced objects
/// </summary>
/// <typeparam name="TCloned">Type of the object that will be cloned</typeparam>
/// <param name="objectToClone">Object that will be cloned</param>
/// <param name="usePropertyBasedClone">
/// Whether to clone the object based on its properties only
/// </param>
/// <returns>A shallow clone of the provided object</returns>
/// <remarks>
/// <para>
/// 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.
/// </para>
/// <para>
/// 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.
/// </para>
/// </remarks>
TCloned ShallowClone<TCloned>(TCloned objectToClone, bool usePropertyBasedClone);
TCloned ShallowPropertyClone<TCloned>(TCloned objectToClone);
/// <summary>
/// Creates a deep clone of the specified object, also creating clones of all
/// child objects being referenced
/// </summary>
/// <typeparam name="TCloned">Type of the object that will be cloned</typeparam>
/// <param name="objectToClone">Object that will be cloned</param>
/// <returns>A deep clone of the provided object</returns>
/// <remarks>
/// 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.
/// </remarks>
TCloned DeepFieldClone<TCloned>(TCloned objectToClone);
/// <summary>
/// Creates a deep clone of the specified object, also creating clones of all
/// child objects being referenced
/// </summary>
/// <typeparam name="TCloned">Type of the object that will be cloned</typeparam>
/// <param name="objectToClone">Object that will be cloned</param>
/// <returns>A deep clone of the provided object</returns>
/// <remarks>
/// <para>
/// 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.
/// </para>
/// <para>
/// 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.
/// </para>
/// </remarks>
TCloned DeepPropertyClone<TCloned>(TCloned objectToClone);
}

View File

@ -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<int>(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 });
List<int> clone = this.cloneFactory.DeepClone(original, false);
List<int> clone = this.cloneFactory.DeepFieldClone(original);
CollectionAssert.AreEqual(original, clone);
}
@ -82,7 +82,7 @@ namespace Nuclex.Support.Cloning {
public void GenericDictionariesCanBeCloned() {
var original = new Dictionary<int, string>();
original.Add(1, "one");
Dictionary<int, string> clone = this.cloneFactory.DeepClone(original, false);
Dictionary<int, string> 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);
}

View File

@ -39,52 +39,19 @@ namespace Nuclex.Support.Cloning {
/// </summary>
/// <typeparam name="TCloned">Type of the object that will be cloned</typeparam>
/// <param name="objectToClone">Object that will be cloned</param>
/// <param name="usePropertyBasedClone">
/// Whether to clone the object based on its properties only
/// </param>
/// <returns>A shallow clone of the provided object</returns>
public static TCloned ShallowClone<TCloned>(
TCloned objectToClone, bool usePropertyBasedClone
) {
public static TCloned ShallowFieldClone<TCloned>(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
}
} else {
if(usePropertyBasedClone) {
return (TCloned)shallowCloneComplexPropertyBased(objectToClone);
} else {
return (TCloned)shallowCloneComplexFieldBased(objectToClone);
}
}
}
/// <summary>
/// Creates a deep clone of the specified object, also creating clones of all
/// child objects being referenced
/// </summary>
/// <typeparam name="TCloned">Type of the object that will be cloned</typeparam>
/// <param name="objectToClone">Object that will be cloned</param>
/// <param name="usePropertyBasedClone">
/// Whether to clone the object based on its properties only
/// </param>
/// <returns>A deep clone of the provided object</returns>
public static TCloned DeepClone<TCloned>(
TCloned objectToClone, bool usePropertyBasedClone
) {
if(usePropertyBasedClone) {
return (TCloned)deepCloneSinglePropertyBased(objectToClone);
} else {
return (TCloned)deepCloneSingleFieldBased(objectToClone);
}
}
/// <summary>
/// Creates a shallow clone of the specified object, reusing any referenced objects
@ -95,10 +62,17 @@ namespace Nuclex.Support.Cloning {
/// Whether to clone the object based on its properties only
/// </param>
/// <returns>A shallow clone of the provided object</returns>
TCloned ICloneFactory.ShallowClone<TCloned>(
TCloned objectToClone, bool usePropertyBasedClone
) {
return ReflectionCloner.ShallowClone<TCloned>(objectToClone, usePropertyBasedClone);
public static TCloned ShallowPropertyClone<TCloned>(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);
}
}
/// <summary>
@ -107,12 +81,62 @@ namespace Nuclex.Support.Cloning {
/// </summary>
/// <typeparam name="TCloned">Type of the object that will be cloned</typeparam>
/// <param name="objectToClone">Object that will be cloned</param>
/// <param name="usePropertyBasedClone">
/// Whether to clone the object based on its properties only
/// </param>
/// <returns>A deep clone of the provided object</returns>
TCloned ICloneFactory.DeepClone<TCloned>(TCloned objectToClone, bool usePropertyBasedClone) {
return ReflectionCloner.DeepClone<TCloned>(objectToClone, usePropertyBasedClone);
public static TCloned DeepFieldClone<TCloned>(TCloned objectToClone) {
return (TCloned)deepCloneSingleFieldBased(objectToClone);
}
/// <summary>
/// Creates a deep clone of the specified object, also creating clones of all
/// child objects being referenced
/// </summary>
/// <typeparam name="TCloned">Type of the object that will be cloned</typeparam>
/// <param name="objectToClone">Object that will be cloned</param>
/// <returns>A deep clone of the provided object</returns>
public static TCloned DeepPropertyClone<TCloned>(TCloned objectToClone) {
return (TCloned)deepCloneSinglePropertyBased(objectToClone);
}
/// <summary>
/// Creates a shallow clone of the specified object, reusing any referenced objects
/// </summary>
/// <typeparam name="TCloned">Type of the object that will be cloned</typeparam>
/// <param name="objectToClone">Object that will be cloned</param>
/// <returns>A shallow clone of the provided object</returns>
TCloned ICloneFactory.ShallowFieldClone<TCloned>(TCloned objectToClone) {
return ReflectionCloner.ShallowFieldClone<TCloned>(objectToClone);
}
/// <summary>
/// Creates a shallow clone of the specified object, reusing any referenced objects
/// </summary>
/// <typeparam name="TCloned">Type of the object that will be cloned</typeparam>
/// <param name="objectToClone">Object that will be cloned</param>
/// <returns>A shallow clone of the provided object</returns>
TCloned ICloneFactory.ShallowPropertyClone<TCloned>(TCloned objectToClone) {
return ReflectionCloner.ShallowPropertyClone<TCloned>(objectToClone);
}
/// <summary>
/// Creates a deep clone of the specified object, also creating clones of all
/// child objects being referenced
/// </summary>
/// <typeparam name="TCloned">Type of the object that will be cloned</typeparam>
/// <param name="objectToClone">Object that will be cloned</param>
/// <returns>A deep clone of the provided object</returns>
TCloned ICloneFactory.DeepFieldClone<TCloned>(TCloned objectToClone) {
return ReflectionCloner.DeepFieldClone<TCloned>(objectToClone);
}
/// <summary>
/// Creates a deep clone of the specified object, also creating clones of all
/// child objects being referenced
/// </summary>
/// <typeparam name="TCloned">Type of the object that will be cloned</typeparam>
/// <param name="objectToClone">Object that will be cloned</param>
/// <returns>A deep clone of the provided object</returns>
TCloned ICloneFactory.DeepPropertyClone<TCloned>(TCloned objectToClone) {
return ReflectionCloner.DeepPropertyClone<TCloned>(objectToClone);
}
/// <summary>Clones a complex type using field-based value transfer</summary>

View File

@ -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<int>(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 });
List<int> clone = this.cloneFactory.DeepClone(original, false);
List<int> clone = this.cloneFactory.DeepFieldClone(original);
CollectionAssert.AreEqual(original, clone);
}
@ -71,7 +71,7 @@ namespace Nuclex.Support.Cloning {
public void GenericDictionariesCanBeCloned() {
var original = new Dictionary<int, string>();
original.Add(1, "one");
Dictionary<int, string> clone = this.cloneFactory.DeepClone(original, false);
Dictionary<int, string> 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);
}

View File

@ -242,25 +242,14 @@ namespace Nuclex.Support.Cloning {
/// </summary>
/// <typeparam name="TCloned">Type of the object that will be cloned</typeparam>
/// <param name="objectToClone">Object that will be cloned</param>
/// <param name="usePropertyBasedClone">
/// Whether to clone the object based on its properties only
/// </param>
/// <returns>A deep clone of the provided object</returns>
public static TCloned DeepClone<TCloned>(
TCloned objectToClone, bool usePropertyBasedClone
) {
public static TCloned DeepFieldClone<TCloned>(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);
}
}
}
/// <summary>
/// Creates a deep clone of the specified object, also creating clones of all
@ -268,14 +257,13 @@ namespace Nuclex.Support.Cloning {
/// </summary>
/// <typeparam name="TCloned">Type of the object that will be cloned</typeparam>
/// <param name="objectToClone">Object that will be cloned</param>
/// <param name="usePropertyBasedClone">
/// Whether to clone the object based on its properties only
/// </param>
/// <returns>A deep clone of the provided object</returns>
TCloned ICloneFactory.DeepClone<TCloned>(
TCloned objectToClone, bool usePropertyBasedClone
) {
return SerializationCloner.DeepClone<TCloned>(objectToClone, usePropertyBasedClone);
public static TCloned DeepPropertyClone<TCloned>(TCloned objectToClone) {
using(var memoryStream = new MemoryStream()) {
propertyBasedFormatter.Serialize(memoryStream, objectToClone);
memoryStream.Position = 0;
return (TCloned)propertyBasedFormatter.Deserialize(memoryStream);
}
}
/// <summary>
@ -283,16 +271,43 @@ namespace Nuclex.Support.Cloning {
/// </summary>
/// <typeparam name="TCloned">Type of the object that will be cloned</typeparam>
/// <param name="objectToClone">Object that will be cloned</param>
/// <param name="usePropertyBasedClone">
/// Whether to clone the object based on its properties only
/// </param>
/// <returns>A shallow clone of the provided object</returns>
TCloned ICloneFactory.ShallowClone<TCloned>(
TCloned objectToClone, bool usePropertyBasedClone
) {
TCloned ICloneFactory.ShallowFieldClone<TCloned>(TCloned objectToClone) {
throw new NotSupportedException("The serialization cloner cannot create shallow clones");
}
/// <summary>
/// Creates a shallow clone of the specified object, reusing any referenced objects
/// </summary>
/// <typeparam name="TCloned">Type of the object that will be cloned</typeparam>
/// <param name="objectToClone">Object that will be cloned</param>
/// <returns>A shallow clone of the provided object</returns>
TCloned ICloneFactory.ShallowPropertyClone<TCloned>(TCloned objectToClone) {
throw new NotSupportedException("The serialization cloner cannot create shallow clones");
}
/// <summary>
/// Creates a deep clone of the specified object, also creating clones of all
/// child objects being referenced
/// </summary>
/// <typeparam name="TCloned">Type of the object that will be cloned</typeparam>
/// <param name="objectToClone">Object that will be cloned</param>
/// <returns>A deep clone of the provided object</returns>
TCloned ICloneFactory.DeepFieldClone<TCloned>(TCloned objectToClone) {
return SerializationCloner.DeepFieldClone<TCloned>(objectToClone);
}
/// <summary>
/// Creates a deep clone of the specified object, also creating clones of all
/// child objects being referenced
/// </summary>
/// <typeparam name="TCloned">Type of the object that will be cloned</typeparam>
/// <param name="objectToClone">Object that will be cloned</param>
/// <returns>A deep clone of the provided object</returns>
TCloned ICloneFactory.DeepPropertyClone<TCloned>(TCloned objectToClone) {
return SerializationCloner.DeepPropertyClone<TCloned>(objectToClone);
}
/// <summary>Serializes objects by storing their fields</summary>
private static BinaryFormatter fieldBasedFormatter;
/// <summary>Serializes objects by storing their properties</summary>