#nullable enable using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Swan.Lite.Reflection; using Swan.Mappers; using Swan.Reflection; namespace Swan { /// /// Extension methods. /// public static partial class Extensions { /// /// Iterates over the public, instance, readable properties of the source and /// tries to write a compatible value to a public, instance, writable property in the destination. /// /// The type of the source. /// The source. /// The target. /// The ignore properties. /// /// Number of properties that was copied successful. /// public static Int32 CopyPropertiesTo(this T source, Object? target, params String[]? ignoreProperties) where T : class => ObjectMapper.Copy(source, target, GetCopyableProperties(target), ignoreProperties); /*/// /// Iterates over the public, instance, readable properties of the source and /// tries to write a compatible value to a public, instance, writable property in the destination. /// /// The source. /// The destination. /// Properties to copy. /// /// Number of properties that were successfully copied. /// public static Int32 CopyOnlyPropertiesTo(this Object source, Object target, params String[]? propertiesToCopy) => ObjectMapper.Copy(source, target, propertiesToCopy);*/ /// /// Copies the properties to new instance of T. /// /// The new object type. /// The source. /// The ignore properties. /// /// The specified type with properties copied. /// /// source. public static T CopyPropertiesToNew(this Object source, String[]? ignoreProperties = null) where T : class { if(source == null) { throw new ArgumentNullException(nameof(source)); } T target = Activator.CreateInstance(); _ = ObjectMapper.Copy(source, target, GetCopyableProperties(target), ignoreProperties); return target; } /*/// /// Copies the only properties to new instance of T. /// /// Object Type. /// The source. /// The properties to copy. /// /// The specified type with properties copied. /// /// source. public static T CopyOnlyPropertiesToNew(this Object source, params String[] propertiesToCopy) where T : class { if(source == null) { throw new ArgumentNullException(nameof(source)); } T target = Activator.CreateInstance(); _ = ObjectMapper.Copy(source, target, propertiesToCopy); return target; } /// /// Iterates over the keys of the source and tries to write a compatible value to a public, /// instance, writable property in the destination. /// /// The source. /// The target. /// The ignore keys. /// Number of properties that was copied successful. public static Int32 CopyKeyValuePairTo(this IDictionary source, Object? target, params String[] ignoreKeys) => source == null ? throw new ArgumentNullException(nameof(source)) : ObjectMapper.Copy(source, target, null, ignoreKeys); /// /// Iterates over the keys of the source and tries to write a compatible value to a public, /// instance, writable property in the destination. /// /// Object Type. /// The source. /// The ignore keys. /// /// The specified type with properties copied. /// public static T CopyKeyValuePairToNew(this IDictionary source, params String[] ignoreKeys) { if(source == null) { throw new ArgumentNullException(nameof(source)); } T target = Activator.CreateInstance(); _ = source.CopyKeyValuePairTo(target, ignoreKeys); return target; } /// /// Does the specified action. /// /// The action. /// The retry interval. /// The retry count. public static void Retry(this Action action, TimeSpan retryInterval = default, Int32 retryCount = 3) { if(action == null) { throw new ArgumentNullException(nameof(action)); } _ = Retry(() => { action(); return null; }, retryInterval, retryCount); } /// /// Does the specified action. /// /// The type of the source. /// The action. /// The retry interval. /// The retry count. /// /// The return value of the method that this delegate encapsulates. /// /// action. /// Represents one or many errors that occur during application execution. public static T Retry(this Func action, TimeSpan retryInterval = default, Int32 retryCount = 3) { if(action == null) { throw new ArgumentNullException(nameof(action)); } if(retryInterval == default) { retryInterval = TimeSpan.FromSeconds(1); } global::System.Collections.Generic.List exceptions = new List(); for(Int32 retry = 0; retry < retryCount; retry++) { try { if(retry > 0) { Task.Delay(retryInterval).Wait(); } return action(); } catch(Exception ex) { exceptions.Add(ex); } } throw new AggregateException(exceptions); }*/ /// /// Gets the copyable properties. /// /// If there is no properties with the attribute AttributeCache returns all the properties. /// /// The object. /// /// Array of properties. /// /// model. /// public static IEnumerable GetCopyableProperties(this Object? @this) { if(@this == null) { throw new ArgumentNullException(nameof(@this)); } global::System.Collections.Generic.IEnumerable collection = PropertyTypeCache.DefaultCache.Value.RetrieveAllProperties(@this.GetType(), true); global::System.Collections.Generic.IEnumerable properties = collection.Select(x => new { x.Name, HasAttribute = AttributeCache.DefaultCache.Value.RetrieveOne(x) != null, }).Where(x => x.HasAttribute).Select(x => x.Name); return properties.Any() ? properties : collection.Select(x => x.Name); } internal static void CreateTarget(this Object source, Type targetType, Boolean includeNonPublic, ref Object? target) { switch(source) { // do nothing. Simply skip creation case String _: break; // When using arrays, there is no default constructor, attempt to build a compatible array case IList sourceObjectList when targetType.IsArray: Type? elementType = targetType.GetElementType(); if(elementType != null) { target = Array.CreateInstance(elementType, sourceObjectList.Count); } break; default: IEnumerable> constructors = ConstructorTypeCache.DefaultCache.Value.RetrieveAllConstructors(targetType, includeNonPublic); // Try to check if empty constructor is available if(constructors.Any(x => x.Item2.Length == 0)) { target = Activator.CreateInstance(targetType, includeNonPublic); } else { Tuple firstCtor = constructors.OrderBy(x => x.Item2.Length).FirstOrDefault(); target = Activator.CreateInstance(targetType, firstCtor?.Item2.Select(arg => arg.GetType().GetDefault()).ToArray()); } break; } } internal static String GetNameWithCase(this String name, JsonSerializerCase jsonSerializerCase) => jsonSerializerCase switch { JsonSerializerCase.PascalCase => Char.ToUpperInvariant(name[0]) + name.Substring(1), JsonSerializerCase.CamelCase => Char.ToLowerInvariant(name[0]) + name.Substring(1), JsonSerializerCase.None => name, _ => throw new ArgumentOutOfRangeException(nameof(jsonSerializerCase), jsonSerializerCase, null) }; } }