Created
June 22, 2018 23:28
-
-
Save sbarisic/02bf336afd6c1abd6864672eafb22a04 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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