using Newtonsoft.Json; using Newtonsoft.Json.Converters; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using Tango.Core.Json; using Tango.Serialization; namespace Tango.Core.ExtensionMethods { public enum MappingFlags { /// /// All properties will be mapped. /// All = 1, /// /// Do not map string properties. /// NoStrings = 2, /// /// Do not map string properties with value of null. /// NoNullStrings = 4, /// /// Do not map reference types. /// NoReferenceTypes = 8, /// /// Map only value types. /// ValueTypesOnly, } /// /// Contains extension methods. /// public static class ObjectExtensions { private static bool _jsonSettingsSet; /// /// Performs shallow cloning of the object excluding generic properties.. /// /// /// The object. /// public static T ShallowClone(this T obj) { var cloned = Activator.CreateInstance(); foreach (var prop in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(x => x.SetMethod != null)) { if (!prop.PropertyType.IsGenericTypeAndNotNullable()) { prop.SetValue(cloned, prop.GetValue(obj)); } } return cloned; } /// /// Performs a shallow mapping to the specified object excluding generic properties. /// /// /// The source. /// The destination object. public static void ShallowCopyTo(this T source, T destination) { foreach (var prop in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(x => x.SetMethod != null)) { if (!prop.PropertyType.IsGenericTypeAndNotNullable()) { prop.SetValue(destination, prop.GetValue(source)); } } } /// /// Maps the object primitive properties values to the destination object. /// /// The source object. /// The destination object. /// The mapping flags. /// Optional condition. public static void MapPropertiesTo(this object source, object destination, MappingFlags flags = MappingFlags.NoReferenceTypes, Func condition = null) { foreach (var prop in source.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)) { var propType = prop.PropertyType; var value = prop.GetValue(source); if (condition != null) { if (!condition(prop)) continue; } if (!propType.IsValueType && flags.HasFlag(MappingFlags.ValueTypesOnly)) { continue; } if (propType == typeof(String) && flags.HasFlag(MappingFlags.NoStrings)) { continue; } if (propType.IsClass && propType != typeof(String) && flags.HasFlag(MappingFlags.NoReferenceTypes)) { continue; } if (flags.HasFlag(MappingFlags.NoNullStrings) && propType == typeof(String) && String.IsNullOrEmpty(value as String)) { continue; } var desProp = destination.GetType().GetProperty(prop.Name, BindingFlags.Public | BindingFlags.Instance); if (desProp != null && desProp.SetMethod != null && desProp.PropertyType.IsEnum && prop.PropertyType.IsEnum) { desProp.SetValue(destination, Enum.Parse(desProp.PropertyType, value.ToString())); } else if (desProp != null && desProp.PropertyType == prop.PropertyType && desProp.SetMethod != null) { desProp.SetValue(destination, value); } } } /// /// Maps the object primitive properties values to the destination object. /// /// The source. /// The destination. public static void MapPrimitivesTo(this object source, object destination) { source.MapPropertiesTo(destination, MappingFlags.ValueTypesOnly); } /// /// Serializes the specified object to indented json string. /// /// The object. /// public static String ToJsonString(this Object obj) { if (obj == null) return "null"; if (!_jsonSettingsSet) { JsonConvert.DefaultSettings = (() => { var settings = new JsonSerializerSettings(); settings.Converters.Add(new StringEnumConverter { CamelCaseText = false }); settings.ContractResolver = new ProtobufContractResolver(); return settings; }); _jsonSettingsSet = true; } return JsonConvert.SerializeObject(obj, Formatting.Indented); } /// /// Serializes the specified object to indented json string. /// /// The object. /// public static String ToJsonString(this Object obj, params String[] ignoreProperties) { var settings = new JsonSerializerSettings() { ContractResolver = new DynamicContractResolver(ignoreProperties) }; settings.Converters.Add(new StringEnumConverter { CamelCaseText = false }); return JsonConvert.SerializeObject(obj, Formatting.Indented, settings); } /// /// Serializes the specified object to indented json html string. /// /// The object. /// public static String ToHtmlJsonString(this Object obj, params String[] ignoreProperties) { var settings = new JsonSerializerSettings() { ContractResolver = new HtmlContractResolver(ignoreProperties) }; settings.Converters.Add(new StringEnumConverter { CamelCaseText = false }); return JsonConvert.SerializeObject(obj, Formatting.Indented, settings); } /// /// Gets the property value by the specified path (e.g DateTime.Date.Days). /// /// The object. /// The property path. /// public static Object GetPropertyValueByPath(this object obj, String propertyPath) { if (propertyPath != null) { if (propertyPath.Contains('.')) { string[] Split = propertyPath.Split('.'); string RemainingProperty = propertyPath.Substring(propertyPath.IndexOf('.') + 1); return GetPropertyValueByPath(obj.GetType().GetProperty(Split[0]).GetValue(obj, null), RemainingProperty); } else { var prop = obj.GetType().GetProperty(propertyPath); if (prop != null) { return prop.GetValue(obj, null); } else { return obj.ToString(); } } } else { return obj.ToString(); } } /// /// Sets the property value by the specified path (e.g DateTime.Date.Days). /// /// The object. /// The property path. /// public static void SetPropertyValueByPath(this object obj, String propertyPath, object value) { if (propertyPath != null) { if (propertyPath.Contains('.')) { string[] Split = propertyPath.Split('.'); string RemainingProperty = propertyPath.Substring(propertyPath.IndexOf('.') + 1); SetPropertyValueByPath(obj.GetType().GetProperty(Split[0]).GetValue(obj, null), RemainingProperty, value); } else { obj.GetType().GetProperty(propertyPath).SetValue(obj, value); } } } } }