#nullable enable using System; using System.Collections; using System.Collections.Generic; using System.Linq; 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); /// /// 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; } /// /// 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) }; } }