Beispiel #1
0
        /// <inheritdoc/>
        protected override IEnumerable Copy(IEnumerable source, DuplicatorChainer duplicator)
        {
            if (duplicator == null)
            {
                throw new ArgumentNullException(nameof(duplicator));
            }
            if (source == null)
            {
                return(source);
            }

            Type type = source.GetType();

            if (type.IsArray)
            {
                return(CopyContents(source, duplicator));
            }
#if NETSTANDARD // Constructor missing in .NET full.
            else if (type.AsGenericType() == typeof(Dictionary <,>))
            {
                dynamic result = Activator.CreateInstance(type);
                foreach (dynamic item in CopyContents(source, duplicator))
                {
                    result.Add(item.Key, item.Value);
                }
                return(result);
            }
#endif
            else
            {
                return((IEnumerable)Activator.CreateInstance(type, CopyContents(source, duplicator)));
            }
        }
        /// <inheritdoc/>
        protected internal override (bool, object) TryCopy(object source, DuplicatorChainer duplicator)
        {
            if (duplicator == null)
            {
                throw new ArgumentNullException(nameof(duplicator));
            }
            if (source == null)
            {
                return(true, null);
            }

            Type sourceType = source.GetType();

            if (sourceType.Inherits(typeof(IAsyncEnumerable <>)))
            {
                return(true, GetType()
                       .GetMethod(nameof(CopyAsync), BindingFlags.Static | BindingFlags.NonPublic)
                       .MakeGenericMethod(sourceType.GetGenericArguments().Single())
                       .Invoke(null, new object[] { source, duplicator }));
            }
            else
            {
                return(false, null);
            }
        }
Beispiel #3
0
        /// <inheritdoc/>
        protected internal sealed override (bool, object) TryCopy(object source, DuplicatorChainer duplicator)
        {
            if (duplicator == null)
            {
                throw new ArgumentNullException(nameof(duplicator));
            }
            if (source == null)
            {
                return(true, null);
            }

            if (source is TimeSpan span)
            {
                return(true, new TimeSpan(duplicator.Copy(span.Ticks)));
            }
            else if (source is Uri link)
            {
                return(true, new Uri(link.OriginalString));
            }
            else if (source is WeakReference reference)
            {
                return(true, new WeakReference(reference.Target, reference.TrackResurrection));
            }
            else if (source is MemberInfo member)
            {
                return(true, member);
            }
            else
            {
                return(false, null);
            }
        }
        /// <summary>Deep clones <paramref name="source"/>.</summary>
        /// <param name="source">Object to clone.</param>
        /// <param name="duplicator">Handles callback behavior for child values.</param>
        /// <returns>Clone of <paramref name="source"/>.</returns>
        private static object Copy(object source, DuplicatorChainer duplicator)
        {
            object dupe = CreateNew(source, duplicator);

            if (dupe == null)
            {
                return(dupe);
            }
            duplicator.AddToHistory(source, dupe);

            foreach (FieldInfo field in source.GetType()
                     .GetFields(BindingFlags.Instance | BindingFlags.Public)
                     .Where(f => !f.IsInitOnly && !f.IsLiteral))
            {
                field.SetValue(dupe, duplicator.Copy(field.GetValue(source)));
            }

            foreach (PropertyInfo property in source.GetType()
                     .GetProperties(BindingFlags.Instance | BindingFlags.Public)
                     .Where(p => p.CanRead && p.CanWrite))
            {
                property.SetValue(dupe, duplicator.Copy(property.GetValue(source)));
            }

            return(dupe);
        }
Beispiel #5
0
        /// <summary>Copies the contents of <paramref name="source"/>.</summary>
        /// <param name="source">Collection with contents to copy.</param>
        /// <param name="duplicator">Handles callback behavior for child values.</param>
        /// <returns>Clone of <paramref name="source"/>'s elements.</returns>
        private static IEnumerable CopyContents(IEnumerable source, DuplicatorChainer duplicator)
        {
            Type type        = source.GetType();
            Type genericType = type.AsGenericType();

            object[] data = CopyContentsHelper(source, duplicator,
                                               _ReverseCases.Contains(genericType ?? type));

            if (genericType != null)
            {
                Type[] args     = type.GetGenericArguments();
                Type   itemType = (args.Length != 1)
                    ? typeof(KeyValuePair <,>).MakeGenericType(args)
                    : args.Single();

                return(ArrayCast(itemType, data));
            }
            else if (type.IsArray)
            {
                return(ArrayCast(type.GetElementType(), data));
            }
            else
            {
                return(data);
            }
        }
        /// <inheritdoc/>
        protected override IDuplicatable Copy(IDuplicatable source, DuplicatorChainer duplicator)
        {
            if (duplicator == null)
            {
                throw new ArgumentNullException(nameof(duplicator));
            }

            return(source?.DeepClone(duplicator.Duplicator));
        }
        /// <summary>Attempts to create an instance using a <paramref name="constructor"/>.</summary>
        /// <param name="source">Object being cloned.</param>
        /// <param name="duplicator">Handles callback behavior for child values.</param>
        /// <param name="constructor">Constructor on <paramref name="source"/> to use.</param>
        /// <param name="props">Properties on <paramref name="source"/>.</param>
        /// <param name="fields">Fields on <paramref name="source"/>.</param>
        /// <returns>Null if failed; created instance otherwise.</returns>
        private static object TryCreate(object source, DuplicatorChainer duplicator,
                                        ConstructorInfo constructor, IEnumerable <PropertyInfo> props, IEnumerable <FieldInfo> fields)
        {
            List <PropertyInfo> propList  = props.ToList();
            List <FieldInfo>    fieldList = fields.ToList();

            // Attempts to match members with parameters in the constructor.
            List <MemberInfo> matchedMembers = new();

            foreach (ParameterInfo param in constructor.GetParameters())
            {
                PropertyInfo[] potentialProps = propList
                                                .Where(p => p.PropertyType.Inherits(param.ParameterType))
                                                .ToArray();
                if (potentialProps.Any())
                {
                    PropertyInfo directPropMatch = potentialProps.FirstOrDefault(
                        p => p.Name.Equals(param.Name, StringComparison.OrdinalIgnoreCase));
                    if (directPropMatch != null)
                    {
                        _ = propList.Remove(directPropMatch);
                        matchedMembers.Add(directPropMatch);
                    }
                    else
                    {
                        _ = propList.Remove(potentialProps.First());
                        matchedMembers.Add(potentialProps.First());
                    }
                    continue;
                }

                FieldInfo[] potentialFields = fieldList
                                              .Where(f => f.FieldType.Inherits(param.ParameterType))
                                              .ToArray();
                if (potentialFields.Any())
                {
                    FieldInfo directFieldMatch = potentialFields.FirstOrDefault(
                        f => f.Name.Equals(param.Name, StringComparison.OrdinalIgnoreCase));
                    if (directFieldMatch != null)
                    {
                        _ = fieldList.Remove(directFieldMatch);
                        matchedMembers.Add(directFieldMatch);
                    }
                    else
                    {
                        _ = fieldList.Remove(potentialFields.First());
                        matchedMembers.Add(potentialFields.First());
                    }
                    continue;
                }

                return(null);
            }

            return(constructor.Invoke(matchedMembers.Select(m => CopyMember(m, source, duplicator)).ToArray()));
        }
 /// <summary>Copies the value of <paramref name="member"/> on <paramref name="source"/>.</summary>
 /// <param name="member">Property or field to copy.</param>
 /// <param name="source">Instance containing the member.</param>
 /// <param name="duplicator">Duplicator handling the cloning.</param>
 /// <returns>The duplicate object.</returns>
 private static object CopyMember(MemberInfo member, object source, DuplicatorChainer duplicator)
 {
     if (member is PropertyInfo prop)
     {
         return(duplicator.Copy(prop.GetValue(source)));
     }
     else
     {
         return(duplicator.Copy(((FieldInfo)member).GetValue(source)));
     }
 }
Beispiel #9
0
        /// <inheritdoc/>
        protected internal sealed override (bool, object) TryCopy(object source, DuplicatorChainer duplicator)
        {
            if (duplicator == null)
            {
                throw new ArgumentNullException(nameof(duplicator));
            }
            if (source == null)
            {
                return(true, null);
            }

            if (source is Task task && task.GetType().IsGenericType)
            {
                return(true, Copy(task, duplicator));
            }
        /// <inheritdoc/>
        protected internal sealed override (bool, object) TryCopy(object source, DuplicatorChainer duplicator)
        {
            if (duplicator == null)
            {
                throw new ArgumentNullException(nameof(duplicator));
            }
            if (source == null)
            {
                return(true, null);
            }

            object result = Copy(source, duplicator);

            return(result != null, result);
        }
Beispiel #11
0
        /// <summary>Copies the contents of <paramref name="source"/>.</summary>
        /// <param name="source">Collection with contents to copy.</param>
        /// <param name="duplicator">Handles callback behavior for child values.</param>
        /// <param name="reverse">If the copy process should reverse the order of items from the enumerator.</param>
        /// <returns>The duplicate object.</returns>
        private static object[] CopyContentsHelper(IEnumerable source, DuplicatorChainer duplicator, bool reverse)
        {
            List <object> copy = new();

            IEnumerator enumerator = source.GetEnumerator();

            while (enumerator.MoveNext())
            {
                copy.Add(duplicator.Copy(enumerator.Current));
            }

            if (reverse)
            {
                copy.Reverse();
            }

            return(copy.ToArray());
        }
        /// <inheritdoc/>
        protected internal sealed override (bool, object) TryCopy(object source, DuplicatorChainer duplicator)
        {
            Type type = source?.GetType();

            if (type == null ||
                type.IsPrimitive ||
                type.IsEnum ||
                ValueRandom.ValueTypes.Contains(type) ||
                type == typeof(object) ||
                type == typeof(string) ||
                type.Inherits <IObjectReference>())
            {
                return(true, source);
            }
            else
            {
                return(false, null);
            }
        }
        /// <summary>Creates an instance of <paramref name="source"/>'s <see cref="Type"/>.</summary>
        /// <param name="source">Object whose <see cref="Type"/> is to be created.</param>
        /// <param name="duplicator">Handles callback behavior for child values.</param>
        /// <returns>The created instance.</returns>
        private static object CreateNew(object source, DuplicatorChainer duplicator)
        {
            Type type = source.GetType();

            if (type.GetConstructor(Type.EmptyTypes) != null)
            {
                return(Activator.CreateInstance(type));
            }
            else
            {
                PropertyInfo[] props  = type.GetProperties(_MemberFlags).Where(p => p.CanRead).ToArray();
                FieldInfo[]    fields = type.GetFields(_MemberFlags).ToArray();

                return(type.GetConstructors(_MemberFlags)
                       .Where(c => !c.IsPrivate)
                       .OrderByDescending(c => c.GetParameters().Length)
                       .Select(c => TryCreate(source, duplicator, c, props, fields))
                       .FirstOrDefault(o => o != null));
            }
        }
        /// <inheritdoc/>
        protected internal override (bool, object) TryCopy(object source, DuplicatorChainer duplicator)
        {
            if (source == null)
            {
                return(true, null);
            }

            if (source is ISerializable && source.GetType().IsSerializable)
            {
                using (Stream stream = new MemoryStream())
                {
                    _Serializer.Serialize(stream, source);
                    _ = stream.Seek(0, SeekOrigin.Begin);
                    return(true, _Serializer.Deserialize(stream));
                }
            }
            else
            {
                return(false, null);
            }
        }
Beispiel #15
0
 /// <inheritdoc/>
 protected internal sealed override (bool, object) TryCopy(object source, DuplicatorChainer duplicator)
 {
     if (source == null)
     {
         return(true, Copy(default, duplicator));
 /// <summary>Deep clones <paramref name="source"/>.</summary>
 /// <typeparam name="T">Item type being copied.</typeparam>
 /// <param name="source">Object to clone.</param>
 /// <param name="duplicator">Handles callback behavior for child values.</param>
 /// <returns>Clone of <paramref name="source"/>.</returns>
 private static async IAsyncEnumerable <T> CopyAsync <T>(IAsyncEnumerable <T> source, DuplicatorChainer duplicator)
 {
     await foreach (T item in source)
     {
         yield return(duplicator.Copy(item));
     }
 }
 /// <inheritdoc/>
 protected override IDeepCloneable Copy(IDeepCloneable source, DuplicatorChainer duplicator)
 {
     return(source?.DeepClone());
 }
Beispiel #18
0
 /// <summary>Tries to deep clone <paramref name="source"/>.</summary>
 /// <param name="source">Object to clone.</param>
 /// <param name="duplicator">Handles callback behavior for child values.</param>
 /// <returns>
 ///     (<c>true</c>, clone of <paramref name="source"/>) if successful;
 ///     (<c>false</c>, <c>null</c>) otherwise.
 /// </returns>
 protected internal abstract (bool, object) TryCopy(object source, DuplicatorChainer duplicator);
 /// <inheritdoc/>
 protected override ICloneable Copy(ICloneable source, DuplicatorChainer duplicator)
 {
     return((ICloneable)source?.Clone());
 }