Beispiel #1
0
 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);
     }
 }
Beispiel #2
0
        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);
        }
Beispiel #3
0
        /// <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;
            }
        }
Beispiel #4
0
        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);
            }
        }
Beispiel #5
0
        /// <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;
        }
Beispiel #6
0
 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);
     }
 }
Beispiel #7
0
        /// <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;
            }
        }
Beispiel #8
0
 public LocalCloneBehavior(TypeInfo targetType, CloneBehavior behavior)
 {
     this.targetType = targetType;
     this.behavior   = behavior;
 }
Beispiel #9
0
        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);
        }
Beispiel #10
0
 public CloneBehaviorAttribute(Type targetType, CloneBehavior behavior)
 {
     this.targetType = targetType;
     this.behavior   = behavior;
 }
Beispiel #11
0
 public CloneBehaviorAttribute(CloneBehavior behavior) : this(null, behavior)
 {
 }
Beispiel #12
0
		public CloneBehaviorAttribute(Type targetType, CloneBehavior behavior)
		{
			this.targetType = targetType;
			this.behavior = behavior;
		}
Beispiel #13
0
		public CloneBehaviorAttribute(CloneBehavior behavior) : this(null, behavior) {}