using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Text.Json;
using System.ComponentModel;
using System.Reflection;
namespace EasyDevCore.Common
{
///
///
///
public static class CopyHelper
{
///
/// Clones the hashtable.
///
/// The input.
///
public static Hashtable CloneHashtable(this Hashtable input)
{
Hashtable ret = new Hashtable();
foreach (DictionaryEntry dictionaryEntry in input)
{
if (dictionaryEntry.Value is string)
{
ret.Add(dictionaryEntry.Key, dictionaryEntry.Value != null ? (string)dictionaryEntry.Value : null);
}
else if (dictionaryEntry.Value is Hashtable)
{
ret.Add(dictionaryEntry.Key, CloneHashtable((Hashtable)dictionaryEntry.Value));
}
else if (dictionaryEntry.Value is ArrayList)
{
ret.Add(dictionaryEntry.Key, new ArrayList((ArrayList)dictionaryEntry.Value));
}
}
return ret;
}
///
/// Clones the specified source.
///
///
/// The source.
/// T.
/// The type must be serializable.;source
public static T CloneObject(this T source)
{
#pragma warning disable SYSLIB0050 // Type or member is obsolete
if (!typeof(T).IsSerializable)
{
throw new ArgumentException("The type must be serializable.", "source");
}
#pragma warning restore SYSLIB0050 // Type or member is obsolete
// Don't serialize a null object, simply return the default for that object
if (source == null)
{
return default(T);
}
var json = JsonSerializer.Serialize(source, source.GetType());
return string.IsNullOrWhiteSpace(json) ? default(T) : (T)JsonSerializer.Deserialize(json, source.GetType());
}
///
/// Simples the map.
///
/// The type of the dest.
/// The source.
/// The update properties.
/// The except properties.
///
public static TDest SimpleMap(this object source, string updateProperties = null, string exceptProperties = null)
where TDest : class, new()
{
var dest = new TDest();
return SimpleMap(source, dest, updateProperties, exceptProperties);
}
///
/// Simples the map.
///
/// The type of the dest.
/// The source.
/// The destination.
/// The update properties.
/// The except properties.
///
public static TDest SimpleMap(this object source, TDest destination, string updateProperties = null, string exceptProperties = null)
where TDest : class
{
Type destType = destination.GetType();
Span sourceProperties = null;
if(string.IsNullOrWhiteSpace(updateProperties))
{
sourceProperties = source.GetType().GetProperties().Where(x => x.CanRead).ToArray().AsSpan();
}
else
{
sourceProperties = (from sp in source.GetType().GetProperties().Where(x => x.CanRead)
join propName in updateProperties.Split(',') on sp.Name equals propName
select sp).ToArray().AsSpan();
}
Span destinationProperties = null;
if (string.IsNullOrWhiteSpace(exceptProperties))
{
destinationProperties = destType.GetProperties().Where(x => x.CanWrite).ToArray().AsSpan();
}
else
{
var exceptPropertiesArray = exceptProperties.Split(',');
destinationProperties = destType.GetProperties().Where(x => exceptPropertiesArray.Contains(x.Name)).Where(x => x.CanWrite).ToArray().AsSpan();
}
for (int si = 0; si < sourceProperties.Length; si++)
{
PropertyInfo sourceProperty = sourceProperties[si];
for (int di = 0; di < destinationProperties.Length; di++)
{
PropertyInfo destinationProperty = destinationProperties[di];
if (sourceProperty.Name.Equals(destinationProperty.Name, StringComparison.InvariantCultureIgnoreCase))
{
var sourceValue = sourceProperty.GetValue(source);
destinationProperty.SetValue(destination, sourceProperty.PropertyType == destinationProperty.PropertyType ? sourceValue : sourceValue.ChangeType(destType));
break;
}
}
}
return destination;
}
///
/// Copies the specified source.
///
/// The type of the source.
/// The type of the dest.
/// The dest.
/// The source.
/// if set to true [case sensitive].
/// The predicate.
/// The setter.
///
public static TDest Copy(this TDest dest, TSource source, bool caseSensitive = false, Func predicate = null, Func setter = null)
where TSource : class
where TDest : class
{
if (source.IsDictionary() && source.HasGenerictArgumentType(0))
{
var props = TypeDescriptor.GetProperties(dest);
var machingNames = from prop in props.OfType()
from val in (IDictionary)source
where prop.Name.Equals(val.Key, (caseSensitive ? StringComparison.InvariantCulture : StringComparison.InvariantCultureIgnoreCase))
&& (predicate == null || predicate(prop.Name, val.Value))
select new { Property = prop, Value = val.Value };
machingNames.ForEach(m => ReflectionHelper.SetPropertyValue(dest, m.Property, (setter == null ? m.Value : setter(m.Property.Name, m.Value))));
}
else
{
var sourceProps = TypeDescriptor.GetProperties(source);
var destProps = TypeDescriptor.GetProperties(dest);
var machingProps = from s in sourceProps.OfType()
from d in destProps.OfType()
where s.Name.Equals(d.Name, (caseSensitive ? StringComparison.InvariantCulture : StringComparison.InvariantCultureIgnoreCase))
&& (predicate == null || predicate(d.Name, s.GetValue(source)))
select new { SourceProp = s, DestProp = d };
machingProps.ForEach(m =>
{
var value = m.SourceProp.GetValue(source);
ReflectionHelper.SetPropertyValue(dest, m.DestProp, (setter == null ? value : setter(m.DestProp.Name, value)));
});
}
return dest;
}
}
}