/// <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); } }
/// <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); }
/// <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))); } }
/// <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); }
/// <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); } }
/// <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()); }
/// <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()); }