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