mirror of
https://github.com/Ellpeck/MLEM.git
synced 2024-11-22 12:58:33 +01:00
Added DeepCopy
This commit is contained in:
parent
ba24707b18
commit
cb369dec75
2 changed files with 59 additions and 11 deletions
|
@ -16,13 +16,27 @@ namespace MLEM.Data {
|
||||||
/// <typeparam name="T">The type of the object to copy</typeparam>
|
/// <typeparam name="T">The type of the object to copy</typeparam>
|
||||||
/// <returns>A shallow copy of the object</returns>
|
/// <returns>A shallow copy of the object</returns>
|
||||||
public static T Copy<T>(this T obj, BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) {
|
public static T Copy<T>(this T obj, BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) {
|
||||||
var copy = (T) typeof(T).GetConstructor(Type.EmptyTypes).Invoke(null);
|
var copy = (T) Construct(typeof(T), flags);
|
||||||
obj.CopyInto(copy, flags);
|
obj.CopyInto(copy, flags);
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Copies the given object <paramref name="obj"/> into the given object <see cref="otherObj"/>.
|
/// Creates a deep copy of the object and returns it.
|
||||||
|
/// Note that, for this to work correctly, <typeparamref name="T"/> needs to contain a parameterless constructor.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The object to create a deep copy of</param>
|
||||||
|
/// <param name="flags">The binding flags for field searching</param>
|
||||||
|
/// <typeparam name="T">The type of the object to copy</typeparam>
|
||||||
|
/// <returns>A deep copy of the object</returns>
|
||||||
|
public static T DeepCopy<T>(this T obj, BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) {
|
||||||
|
var copy = (T) Construct(typeof(T), flags);
|
||||||
|
obj.DeepCopyInto(copy, flags);
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copies the given object <paramref name="obj"/> into the given object <see cref="otherObj"/> in a shallow manner.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="obj">The object to create a shallow copy of</param>
|
/// <param name="obj">The object to create a shallow copy of</param>
|
||||||
/// <param name="otherObj">The object to copy into</param>
|
/// <param name="otherObj">The object to copy into</param>
|
||||||
|
@ -33,5 +47,38 @@ namespace MLEM.Data {
|
||||||
field.SetValue(otherObj, field.GetValue(obj));
|
field.SetValue(otherObj, field.GetValue(obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copies the given object <paramref name="obj"/> into the given object <see cref="otherObj"/> 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The object to create a deep copy of</param>
|
||||||
|
/// <param name="otherObj">The object to copy into</param>
|
||||||
|
/// <param name="flags">The binding flags for field searching</param>
|
||||||
|
/// <typeparam name="T">The type of the object to copy</typeparam>
|
||||||
|
public static void DeepCopyInto<T>(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 (field.FieldType.IsValueType) {
|
||||||
|
// if we're a value type (struct or primitive), we can just set the value
|
||||||
|
field.SetValue(otherObj, val);
|
||||||
|
} else if (val != null) {
|
||||||
|
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);
|
||||||
|
} else {
|
||||||
|
// if the value is null, we ensure that the value of the resulting object is also reset
|
||||||
|
field.SetValue(otherObj, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static object Construct(Type t, BindingFlags flags) {
|
||||||
|
return t.GetConstructor(flags, null, Type.EmptyTypes, null).Invoke(null);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -92,17 +92,19 @@ namespace Sandbox {
|
||||||
var obj = new Test {
|
var obj = new Test {
|
||||||
Vec = new Vector2(10, 20),
|
Vec = new Vector2(10, 20),
|
||||||
Point = new Point(20, 30),
|
Point = new Point(20, 30),
|
||||||
Rectangle = new Rectangle(1, 2, 3, 4),
|
Dir = Direction2.Left,
|
||||||
RectangleF = new RectangleF(4, 5, 6, 7).ToMlem(),
|
OtherTest = new Test {
|
||||||
Dir = Direction2.Left
|
Vec = new Vector2(70, 30),
|
||||||
|
Dir = Direction2.Right
|
||||||
|
}
|
||||||
};
|
};
|
||||||
Console.WriteLine(obj);
|
Console.WriteLine(obj);
|
||||||
|
|
||||||
var copy = obj.Copy();
|
var copy = obj.DeepCopy();
|
||||||
Console.WriteLine(copy);
|
Console.WriteLine(copy);
|
||||||
|
|
||||||
var intoCopy = new Test();
|
var intoCopy = new Test {OtherTest = new Test()};
|
||||||
obj.CopyInto(intoCopy);
|
obj.DeepCopyInto(intoCopy);
|
||||||
Console.WriteLine(intoCopy);
|
Console.WriteLine(intoCopy);
|
||||||
|
|
||||||
var writer = new StringWriter();
|
var writer = new StringWriter();
|
||||||
|
@ -214,12 +216,11 @@ namespace Sandbox {
|
||||||
|
|
||||||
public Vector2 Vec;
|
public Vector2 Vec;
|
||||||
public Point Point;
|
public Point Point;
|
||||||
public Rectangle Rectangle;
|
|
||||||
public MLEM.Misc.RectangleF RectangleF;
|
|
||||||
public Direction2 Dir { get; set; }
|
public Direction2 Dir { get; set; }
|
||||||
|
public Test OtherTest;
|
||||||
|
|
||||||
public override string ToString() {
|
public override string ToString() {
|
||||||
return $"{nameof(this.Vec)}: {this.Vec}, {nameof(this.Point)}: {this.Point}, {nameof(this.Rectangle)}: {this.Rectangle}, {nameof(this.RectangleF)}: {this.RectangleF}, {nameof(this.Dir)}: {this.Dir}";
|
return $"{this.GetHashCode()}: {nameof(this.Vec)}: {this.Vec}, {nameof(this.Point)}: {this.Point}, {nameof(this.OtherTest)}: {this.OtherTest}, {nameof(this.Dir)}: {this.Dir}";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue