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 source. /// The type of the dest. /// The source. /// The destination. /// The update properties (seperator by comma). /// public static TDest SimpleMap(this TSource source, TDest destination = null, string updateProperties = null) where TSource : class where TDest : class { Type destType = typeof(TDest); if (destination == null) { destination = (TDest)Activator.CreateInstance(destType); } Span sourceProperties = null; if(string.IsNullOrWhiteSpace(updateProperties)) { sourceProperties = source.GetType().GetProperties().AsSpan(); } else { sourceProperties = (from sp in source.GetType().GetProperties() join propName in updateProperties.SplitCommaString() on sp.Name equals propName select sp).ToArray().AsSpan(); } var destinationProperties = destType.GetProperties().AsSpan(); for (int si = 0; si < sourceProperties.Length; si++) { PropertyInfo sourceProperty = sourceProperties[si]; for (int di = 0; di < destinationProperties.Length; di++) { PropertyInfo destinationProperty = destinationProperties[si]; if (sourceProperty.Name.Equals(destinationProperty.Name, StringComparison.InvariantCultureIgnoreCase) && destinationProperty.CanWrite) { 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; } } }