Skip to content

Instantly share code, notes, and snippets.

@sbarisic
Created June 22, 2018 23:28
Show Gist options
  • Save sbarisic/02bf336afd6c1abd6864672eafb22a04 to your computer and use it in GitHub Desktop.
Save sbarisic/02bf336afd6c1abd6864672eafb22a04 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using System.IO;
using System.Runtime.Serialization;
using System.ComponentModel;
namespace DeepCopying {
static class DeepCopy {
static FieldInfo[] GetFields(Type T) {
return T.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
}
static PropertyInfo[] GetProperties(Type T) {
return T.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
}
public static T Copy<T>(T Obj) {
return (T)Copy((object)Obj);
}
public static object Copy(object Obj) {
if (Obj == null)
return null;
Type ObjType = Obj.GetType();
if (Obj is string)
return string.Copy((string)Obj);
else if (Obj is Int16 || Obj is Int32 || Obj is Int64 || Obj is UInt16 || Obj is UInt32 || Obj is UInt64)
return Obj;
else if (Obj is byte || Obj is sbyte || Obj is char || Obj is bool)
return Obj;
else if (ObjType.IsArray) {
Array ObjArray = (Array)Obj;
int ArrayRank = ObjType.GetArrayRank();
if (ArrayRank != 1)
throw new Exception("Array of rank not supported " + ArrayRank);
int Len = ObjArray.GetLength(0);
Array NewObjArray = Array.CreateInstance(ObjType.GetElementType(), Len);
for (int i = 0; i < Len; i++)
NewObjArray.SetValue(Copy(ObjArray.GetValue(i)), i);
return NewObjArray;
}
FieldInfo[] AllFields = GetFields(ObjType);
object BoxedNewInstance = FormatterServices.GetUninitializedObject(ObjType);
foreach (var Field in AllFields)
Field.SetValue(BoxedNewInstance, Copy(Field.GetValue(Obj)));
// Makes sure all the getter and setter methods are called when cloning an object.
// No side effects unless the properties are gay and implement ridiculous shit.
PropertyInfo[] AllProperties = GetProperties(ObjType);
foreach (var Prop in AllProperties) {
MethodInfo Get = Prop.GetGetMethod();
MethodInfo Set = Prop.GetSetMethod();
if (Get != null && Set != null && Set.GetParameters().Length == 0)
Set.Invoke(BoxedNewInstance, new object[] { Get.Invoke(BoxedNewInstance, new object[] { }) });
}
return BoxedNewInstance;
}
public static void MergeProperty(object Obj, string Prop, object Val) {
Merge(Obj.GetType().GetProperty(Prop).GetGetMethod().Invoke(Obj, new object[] { }), Val);
Notify(Obj, Prop); // Notify property manually
}
public static void Merge(object MergeInto, object MergeFrom) {
FieldInfo[] AllFields = GetFields(MergeInto.GetType());
object BoxedMergeInto = MergeInto;
foreach (var Field in AllFields)
Field.SetValue(BoxedMergeInto, Field.GetValue(MergeFrom));
MergeInto = BoxedMergeInto;
}
public static void Notify(object Obj, string PropName = null) { // Notify PropName or all properties of an object
INotifyPropertyChanged NPC = Obj as INotifyPropertyChanged;
if (NPC != null) {
//EventInfo OnPropertyChanged = typeof(INotifyPropertyChanged).GetEvent(nameof(INotifyPropertyChanged.PropertyChanged));
//MethodInfo RaiseOnPropertyChanged = OnPropertyChanged.GetRaiseMethod();
FieldInfo FI = Obj.GetType().GetField("PropertyChanged", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
MulticastDelegate RaiseOnPropertyChanged = (MulticastDelegate)FI.GetValue(Obj);
if (RaiseOnPropertyChanged != null) {
if (PropName != null) {
foreach (var Delegate in RaiseOnPropertyChanged.GetInvocationList())
Delegate.DynamicInvoke(new object[] { NPC, new PropertyChangedEventArgs(PropName) });
} else {
PropertyInfo[] AllProperties = GetProperties(Obj.GetType());
foreach (var Prop in AllProperties)
foreach (var Delegate in RaiseOnPropertyChanged.GetInvocationList())
Delegate.DynamicInvoke(new object[] { NPC, new PropertyChangedEventArgs(Prop.Name) });
}
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment