void ICloneTargetSetup.HandleObject <T>(T source, T target, CloneBehavior behavior, TypeInfo behaviorTarget) { if (object.ReferenceEquals(source, this.currentObject)) { this.PrepareObjectChildCloneGraph(this.currentObject, target, this.currentCloneType); } else if (behaviorTarget != null) { this.PushCloneBehavior(new LocalCloneBehavior(behaviorTarget, behavior)); this.PrepareObjectCloneGraph(source, target, null); this.PopCloneBehavior(); } else if (behavior == CloneBehavior.Reference) { return; } else if (behavior == CloneBehavior.WeakReference) { if (!object.ReferenceEquals(source, null)) { this.dropWeakReferences.Add(source); } } else { this.PrepareObjectCloneGraph(source, target, null, behavior); } }
private CloneBehavior GetCloneBehavior(CloneType sourceType, bool lockBehavior, out object acquiredLock) { CloneBehavior defaultBehavior = (sourceType != null) ? sourceType.DefaultCloneBehavior : CloneBehavior.ChildObject; // Local behavior rules acquiredLock = null; var localBehaviorData = this.localBehavior.Data; for (int i = this.localBehavior.Count - 1; i >= 0; i--) { if (localBehaviorData[i].Locked) { continue; } if (localBehaviorData[i].TargetType == null || (sourceType != null && localBehaviorData[i].TargetType.IsAssignableFrom(sourceType.Type))) { acquiredLock = localBehaviorData[i]; localBehaviorData[i].Locked = lockBehavior; CloneBehavior behavior = localBehaviorData[i].Behavior; return((behavior != CloneBehavior.Default) ? behavior : defaultBehavior); } } // Global behavior rules return(defaultBehavior); }
/// <summary> /// Creates a new CloneType based on a <see cref="System.Type"/>, gathering all the information that is necessary for cloning. /// </summary> /// <param name="type"></param> public CloneType(Type type) { this.type = type.GetTypeInfo(); this.copyByAssignment = this.type.IsDeepCopyByAssignment() || typeof(MemberInfo).GetTypeInfo().IsAssignableFrom(this.type); /* Handle MemberInfo like POD */ this.investigateOwnership = !this.copyByAssignment; this.surrogate = CloneProvider.GetSurrogateFor(this.type); if (this.type.IsArray) { if (this.type.GetArrayRank() > 1) { throw new NotSupportedException( "Cloning multidimensional arrays is not supported in Cohee. " + "Consider skipping the referring field via [CloneField] or [DontSerialize] " + "attribute, or use a regular array instead."); } this.elementType = CloneProvider.GetCloneType(this.type.GetElementType()); } CloneBehaviorAttribute defaultBehaviorAttrib = CloneProvider.GetCloneBehaviorAttribute(this.type); if (defaultBehaviorAttrib != null && defaultBehaviorAttrib.Behavior != CloneBehavior.Default) { this.behavior = defaultBehaviorAttrib.Behavior; } else { this.behavior = CloneBehavior.ChildObject; } }
void ICloneTargetSetup.HandleObject <T>(T source, T target, CloneBehavior behavior, TypeInfo behaviorTarget) { // Since "fallback to default" is triggered by source being equal to the currently handled object, // we need to make sure that this cannot be triggered accidentally by auto-generated clone lambdas. // Only allow the fallback when the object in question is actually cloned by user code! bool calledFromUserCode = this.currentObject is ICloneExplicit || this.currentCloneType.Surrogate != null; if (object.ReferenceEquals(source, this.currentObject) && calledFromUserCode) { this.PrepareObjectChildCloneGraph(this.currentObject, target, this.currentCloneType); } else if (behaviorTarget != null) { this.PushCloneBehavior(new LocalCloneBehavior(behaviorTarget, behavior)); this.PrepareObjectCloneGraph(source, target, null); this.PopCloneBehavior(); } else if (behavior == CloneBehavior.Reference) { return; } else { this.PrepareObjectCloneGraph(source, target, null, behavior); } }
/// <summary> /// Creates a new CloneType based on a <see cref="System.Type"/>, gathering all the information that is necessary for cloning. /// </summary> /// <param name="type"></param> public CloneType(Type type) { this.type = type; this.plainOldData = this.type.IsPlainOldData() || typeof(MemberInfo).IsAssignableFrom(this.type); /* Handle MemberInfo like POD */ this.investigateOwnership = !this.plainOldData; this.surrogate = CloneProvider.GetSurrogateFor(this.type); if (this.type.IsArray) this.elementType = CloneProvider.GetCloneType(this.type.GetElementType()); CloneBehaviorAttribute defaultBehaviorAttrib = CloneProvider.GetCloneBehaviorAttribute(this.type); if (defaultBehaviorAttrib != null && defaultBehaviorAttrib.Behavior != CloneBehavior.Default) this.behavior = defaultBehaviorAttrib.Behavior; else this.behavior = CloneBehavior.ChildObject; }
void ICloneTargetSetup.HandleValue <T>(ref T source, ref T target, CloneBehavior behavior, TypeInfo behaviorTarget) { if (typeof(T) == this.currentCloneType.Type.AsType()) { // Structs can't contain themselfs. If source's type is equal to our current clone type, this is a handle-self call. this.PrepareValueChildCloneGraph <T>(ref source, ref target, this.currentCloneType); } else if (behaviorTarget != null) { this.PushCloneBehavior(new LocalCloneBehavior(behaviorTarget, behavior)); this.PrepareValueCloneGraph <T>(ref source, ref target, null); this.PopCloneBehavior(); } else { this.PrepareValueCloneGraph <T>(ref source, ref target, null); } }
/// <summary> /// Creates a new CloneType based on a <see cref="System.Type"/>, gathering all the information that is necessary for cloning. /// </summary> /// <param name="type"></param> public CloneType(Type type) { this.type = type; this.plainOldData = this.type.IsPlainOldData() || typeof(MemberInfo).IsAssignableFrom(this.type); /* Handle MemberInfo like POD */ this.investigateOwnership = !this.plainOldData; this.surrogate = CloneProvider.GetSurrogateFor(this.type); if (this.type.IsArray) { this.elementType = CloneProvider.GetCloneType(this.type.GetElementType()); } CloneBehaviorAttribute defaultBehaviorAttrib = CloneProvider.GetCloneBehaviorAttribute(this.type); if (defaultBehaviorAttrib != null && defaultBehaviorAttrib.Behavior != CloneBehavior.Default) { this.behavior = defaultBehaviorAttrib.Behavior; } else { this.behavior = CloneBehavior.ChildObject; } }
public LocalCloneBehavior(TypeInfo targetType, CloneBehavior behavior) { this.targetType = targetType; this.behavior = behavior; }
private void PrepareObjectCloneGraph(object source, object target, CloneType typeData, CloneBehavior behavior = CloneBehavior.Default) { // Early-out for null values if (object.ReferenceEquals(source, null)) { if (object.ReferenceEquals(target, null)) { return; } if (typeData == null) { typeData = GetCloneType(target.GetType()); } if (!typeData.IsMergeSurrogate) { return; } } // Determine the object Type and early-out if it's just plain old data if (typeData == null) { typeData = GetCloneType(source.GetType()); } if (typeData.IsPlainOldData) { return; } if (typeData.Type.IsValueType && !typeData.InvestigateOwnership) { return; } // Determine cloning behavior for this object object behaviorLock = null; if (!typeData.Type.IsValueType && !object.ReferenceEquals(source, null)) { // If we already registered a target for that source, stop right here. if (this.targetMapping.ContainsKey(source)) { return; } // If no specific behavior was specified, fetch the default one set by class and field attributes if (behavior == CloneBehavior.Default) { behavior = this.GetCloneBehavior(typeData, true, out behaviorLock); } // Apply the current behavior if (behavior != CloneBehavior.ChildObject) { if (behavior == CloneBehavior.WeakReference) { this.dropWeakReferences.Add(source); } this.UnlockCloneBehavior(behaviorLock); return; } // If the target doesn't match the source, discard it if (target != null && target.GetType() != typeData.Type.AsType()) { target = null; } } object lastObject = this.currentObject; CloneType lastCloneType = this.currentCloneType; this.currentObject = source; this.currentCloneType = typeData; // If it's a value type, use the fast lane without surrogate and custom checks if (typeData.Type.IsValueType) { if (object.ReferenceEquals(target, null)) { target = typeData.Type.CreateInstanceOf(); } this.PrepareObjectChildCloneGraph(source, target, typeData); } // Check whether there is a surrogate for this object else if (typeData.Surrogate != null) { bool requireLateSetup; typeData.Surrogate.SetupCloneTargets(source, target, out requireLateSetup, this); if (requireLateSetup) { this.lateSetupSchedule.Add(new LateSetupEntry(source, target)); } } // Otherwise, use the default algorithm else { // Create a new target array. Always necessary due to their immutable size. Array originalTargetArray = null; if (typeData.IsArray) { Array sourceArray = source as Array; originalTargetArray = target as Array; target = Array.CreateInstance(typeData.ElementType.Type.AsType(), sourceArray.Length); } // Only create target object when no reuse is possible else if (object.ReferenceEquals(target, null)) { target = typeData.Type.CreateInstanceOf(); } // Create a mapping from the source object to the target object this.SetTargetOf(source, target); // If we are dealing with an array, use the original one for object reuse mapping if (originalTargetArray != null) { target = originalTargetArray; } // If it implements custom cloning behavior, use that ICloneExplicit customSource = source as ICloneExplicit; if (customSource != null) { customSource.SetupCloneTargets(target, this); } // Otherwise, traverse its child objects using default behavior else { this.PrepareObjectChildCloneGraph(source, target, typeData); } } this.currentObject = lastObject; this.currentCloneType = lastCloneType; this.UnlockCloneBehavior(behaviorLock); }
public CloneBehaviorAttribute(Type targetType, CloneBehavior behavior) { this.targetType = targetType; this.behavior = behavior; }
public CloneBehaviorAttribute(CloneBehavior behavior) : this(null, behavior) { }
public CloneBehaviorAttribute(CloneBehavior behavior) : this(null, behavior) {}