public T Clone <T>(T source) { // Don't clone a null object or immutable objects. Return the identical reference in these cases if (source == null || ImmutableTypeSet.IsImmutableType(source.GetType())) { return(source); } // Try to access current "in-use" ObjectCopierState first ObjectCopierState ocState = usedOcStateTL.Value; if (ocState != null) { // Reuse TL instance. And do not bother with cleanup return(CloneRecursive(source, ocState)); } // No ObjectCopierState "in-use". So we set the TL instance "in-use" and clean it up in the end // because we are responsible for this in this case ocState = AcquireObjectCopierState(); usedOcStateTL.Value = ocState; try { return(CloneRecursive(source, ocState)); } finally { // Clear "in-use" instance usedOcStateTL.Value = null; // Cleanup ObjectCopierState to allow reusage in the same thread later ocState.Clear(); } }
protected Object CloneCollection(Object source, ObjectCopierState ocState) { Type objType = source.GetType(); IEnumerable cloneColl = (IEnumerable)Activator.CreateInstance(objType); ocState.objectToCloneDict.Add(source, cloneColl); // The problem is that .NET does not have a holistic interface to add items to a collection MethodInfo addMethod = cloneColl.GetType().GetMethod("Add"); Object[] args = ocState.addArgs; try { foreach (Object item in (IEnumerable)source) { // Clone each item of the IEnumerable Object cloneItem = CloneRecursive(item, ocState); args[0] = cloneItem; addMethod.Invoke(cloneColl, args); } return(cloneColl); } finally { args[0] = null; } }
protected Object CloneDefault(Object source, ObjectCopierState ocState) { Type objType = source.GetType(); Object clone = Activator.CreateInstance(objType); ocState.objectToCloneDict.Add(source, clone); DeepCloneProperties(source, clone, ocState); return(clone); }
protected ObjectCopierState AcquireObjectCopierState() { // Creates automatically a valid instance if this thread does not already have one ObjectCopierState ocState = ocStateTL.Value; if (ocState == null) { ocState = new ObjectCopierState(this); ocStateTL.Value = ocState; } return(ocState); }
internal void DeepCloneProperties(Object source, Object clone, ObjectCopierState ocState) { IPropertyInfo[] properties = PropertyInfoProvider.GetPrivateProperties(source.GetType()); foreach (IPropertyInfo property in properties) { if (!property.IsWritable) { continue; } Object objValue = property.GetValue(source); Object cloneValue = CloneRecursive(objValue, ocState); property.SetValue(clone, cloneValue); } }
/// <summary> /// Gets called by the ObjectCopierState on custom / default behavior switches /// </summary> internal T CloneRecursive <T>(T source, ObjectCopierState ocState) { // Don't clone a null object or immutable objects. Return the identical reference in these cases if (source == null || ImmutableTypeSet.IsImmutableType(source.GetType())) { return(source); } Type objType = source.GetType(); IdentityDictionary <Object, Object> objectToCloneDict = ocState.objectToCloneDict; Object clone = DictionaryExtension.ValueOrDefault(ocState.objectToCloneDict, source); if (clone != null) { // Object has already been cloned. Cycle detected - we are finished here return((T)clone); } if (objType.IsArray) { return((T)CloneArray(source, ocState)); } if (source is IEnumerable && !(source is String)) { return((T)CloneCollection(source, ocState)); } // Check whether the object will be copied by custom behavior IObjectCopierExtension extension = extensions.GetExtension(objType); if (extension != null) { clone = extension.DeepClone(source, ocState); objectToCloneDict.Add(source, clone); return((T)clone); } // Copy by default behavior return((T)CloneDefault(source, ocState)); }
protected Object CloneArray(Object source, ObjectCopierState ocState) { Type objType = source.GetType(); Array array = (Array)(Object)source; Type elementType = objType.GetElementType(); int length = array.Length; Array cloneArray = Array.CreateInstance(elementType, length); ocState.objectToCloneDict.Add(source, cloneArray); if (ImmutableTypeSet.IsImmutableType(elementType)) { // Clone native array with native functionality for performance reasons Array.Copy(array, cloneArray, length); } else { for (int a = length; a-- > 0;) { // Clone each item of the array cloneArray.SetValue(CloneRecursive(array.GetValue(a), ocState), a); } } return(cloneArray); }