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