using System; using System.Reflection; namespace MLEM.Data { /// /// A set of extensions for dealing with copying objects. /// public static class CopyExtensions { /// /// Creates a shallow copy of the object and returns it. /// Note that, for this to work correctly, needs to contain a parameterless constructor. /// /// The object to create a shallow copy of /// The binding flags for field searching /// The type of the object to copy /// A shallow copy of the object public static T Copy(this T obj, BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) { var copy = (T) Construct(typeof(T), flags); obj.CopyInto(copy, flags); return copy; } /// /// Creates a deep copy of the object and returns it. /// Note that, for this to work correctly, needs to contain a parameterless constructor. /// /// The object to create a deep copy of /// The binding flags for field searching /// The type of the object to copy /// A deep copy of the object public static T DeepCopy(this T obj, BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) { var copy = (T) Construct(typeof(T), flags); obj.DeepCopyInto(copy, flags); return copy; } /// /// Copies the given object into the given object in a shallow manner. /// /// The object to create a shallow copy of /// The object to copy into /// The binding flags for field searching /// The type of the object to copy public static void CopyInto(this T obj, T otherObj, BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) { foreach (var field in typeof(T).GetFields(flags)) field.SetValue(otherObj, field.GetValue(obj)); } /// /// Copies the given object into the given object in a deep manner. /// Note that, for this to work correctly, each type that should be constructed below the topmost level needs to contanin a parameterless constructor. /// /// The object to create a deep copy of /// The object to copy into /// The binding flags for field searching /// The type of the object to copy public static void DeepCopyInto(this T obj, T otherObj, BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) { foreach (var field in obj.GetType().GetFields(flags)) { var val = field.GetValue(obj); if (val == null || field.FieldType.IsValueType) { // if we're a value type (struct or primitive) or null, we can just set the value field.SetValue(otherObj, val); } else { var otherVal = field.GetValue(otherObj); // if the object we want to copy into doesn't have a value yet, we create one if (otherVal == null) { otherVal = Construct(field.FieldType, flags); field.SetValue(otherObj, otherVal); } val.DeepCopyInto(otherVal, flags); } } } private static object Construct(Type t, BindingFlags flags) { return t.GetConstructor(flags, null, Type.EmptyTypes, null).Invoke(null); } } }