Files
mixtape/zero.Core/Utils/ObjectCopycat.cs
T

74 lines
2.3 KiB
C#
Raw Normal View History

2021-11-24 13:56:08 +01:00
using Newtonsoft.Json;
using System.Collections.Concurrent;
2021-11-19 16:11:12 +01:00
using System.Reflection;
2021-11-20 13:52:28 +01:00
namespace zero.Utils;
2021-11-19 16:11:12 +01:00
public class ObjectCopycat
{
const string SEPARATOR = ".";
2021-11-24 15:49:25 +01:00
static readonly Type STRING_TYPE = typeof(string);
2021-11-19 16:11:12 +01:00
static ConcurrentDictionary<string, IEnumerable<PropertyInfo>> PublicPropertiesPerType { get; set; } = new();
2021-11-24 13:56:08 +01:00
public static T Clone<T>(T obj)
{
Type type = obj.GetType();
return (T)JsonConvert.DeserializeObject(JsonConvert.SerializeObject(obj), type);
}
2021-11-19 16:11:12 +01:00
public static T CopyProperties<T>(T source, T target, params string[] exceptions)
{
return CopyPropertiesInternal(source, target, null, exceptions);
}
static T CopyPropertiesInternal<T>(T source, T target, string keyPrefix = null, params string[] exceptions)
{
Type type = source.GetType();
if (!PublicPropertiesPerType.TryGetValue(type.FullName, out IEnumerable<PropertyInfo> properties))
{
properties = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Where(x => x.CanWrite);
PublicPropertiesPerType.TryAdd(type.FullName, properties);
}
foreach (PropertyInfo property in properties)
{
string propertyNameWithPrefix = CombineKey(SEPARATOR, keyPrefix, property.Name);
if (exceptions.Contains(propertyNameWithPrefix, StringComparer.InvariantCultureIgnoreCase))
{
continue;
}
object propertyValue = property.GetValue(source, null);
if (property.PropertyType.IsValueType || property.PropertyType.IsEnum || property.PropertyType.Equals(STRING_TYPE) || propertyValue == null || propertyValue is IEnumerable)
{
property.SetValue(target, propertyValue, null);
}
else if (property.PropertyType.IsClass)
{
string[] nestedExceptions = exceptions.Where(x => x.StartsWith(propertyNameWithPrefix, StringComparison.InvariantCultureIgnoreCase)).ToArray();
property.SetValue(target, CopyPropertiesInternal(propertyValue, property.GetValue(target, null), propertyNameWithPrefix, nestedExceptions), null);
}
}
return target;
}
private static string CombineKey(string sep, string key1, string key2)
{
if (String.IsNullOrEmpty(key1))
{
return key2;
}
return String.Join(sep, key1, key2);
}
}