diff --git a/MLEM.Data/CopyExtensions.cs b/MLEM.Data/CopyExtensions.cs
index e621c05..1c2064f 100644
--- a/MLEM.Data/CopyExtensions.cs
+++ b/MLEM.Data/CopyExtensions.cs
@@ -1,4 +1,5 @@
using System;
+using System.Linq;
using System.Reflection;
namespace MLEM.Data {
@@ -11,7 +12,7 @@ namespace MLEM.Data {
///
/// Creates a shallow copy of the object and returns it.
- /// Note that, for this to work correctly, needs to contain a parameterless constructor.
+ /// Note that, for this to work correctly, needs to contain a parameterless constructor or a constructor with the .
///
/// The object to create a shallow copy of
/// The binding flags for field searching
@@ -26,7 +27,7 @@ namespace MLEM.Data {
///
/// Creates a deep copy of the object and returns it.
- /// Note that, for this to work correctly, needs to contain a parameterless constructor.
+ /// Note that, for this to work correctly, needs to contain a parameterless constructor or a constructor with the .
///
/// The object to create a deep copy of
/// The binding flags for field searching
@@ -56,7 +57,7 @@ namespace MLEM.Data {
///
/// 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.
+ /// Note that, for this to work correctly, each type that should be constructed below the topmost level needs to contanin a parameterless constructor or a constructor with the .
///
/// The object to create a deep copy of
/// The object to copy into
@@ -84,11 +85,23 @@ namespace MLEM.Data {
}
private static object Construct(Type t, BindingFlags flags) {
- var constructor = t.GetConstructor(flags, null, Type.EmptyTypes, null);
+ // find a contructor with the correct attribute
+ var constructor = t.GetConstructors().FirstOrDefault(c => c.GetCustomAttribute() != null);
+ // fall back to a parameterless constructor
if (constructor == null)
- throw new NullReferenceException($"Type {t} does not have a parameterless constructor with the required visibility");
- return constructor.Invoke(null);
+ constructor = t.GetConstructor(flags, null, Type.EmptyTypes, null);
+ if (constructor == null)
+ throw new NullReferenceException($"Type {t} does not have a parameterless constructor with the required visibility or a constructor with the CopyConstructorAttribute");
+ return constructor.Invoke(new object[constructor.GetParameters().Length]);
}
}
+
+ ///
+ /// An attribute that, when added to a constructor, will make that constructor the one used by , and .
+ ///
+ [AttributeUsage(AttributeTargets.Constructor)]
+ public class CopyConstructorAttribute : Attribute {
+
+ }
}
\ No newline at end of file
diff --git a/Sandbox/GameImpl.cs b/Sandbox/GameImpl.cs
index ca23e65..57300dd 100644
--- a/Sandbox/GameImpl.cs
+++ b/Sandbox/GameImpl.cs
@@ -89,11 +89,11 @@ namespace Sandbox {
panel.SetData("TestKey", new Vector2(10, 2));
//Console.WriteLine(panel.GetData("TestKey"));
- var obj = new Test {
+ var obj = new Test(Vector2.One, "test") {
Vec = new Vector2(10, 20),
Point = new Point(20, 30),
Dir = Direction2.Left,
- OtherTest = new Test {
+ OtherTest = new Test(Vector2.One, "other") {
Vec = new Vector2(70, 30),
Dir = Direction2.Right
}
@@ -110,7 +110,7 @@ namespace Sandbox {
var copy = obj.DeepCopy();
Console.WriteLine(copy);
- var intoCopy = new Test {OtherTest = new Test()};
+ var intoCopy = new Test(Vector2.One, "test") {OtherTest = new Test(Vector2.One, "other")};
obj.DeepCopyInto(intoCopy);
Console.WriteLine(intoCopy);
@@ -234,6 +234,11 @@ namespace Sandbox {
public Direction2 Dir { get; set; }
public Test OtherTest;
+ [CopyConstructor]
+ public Test(Vector2 test, string test2) {
+ Console.WriteLine("Constructed with " + test + ", " + test2);
+ }
+
public override string ToString() {
return $"{this.GetHashCode()}: {nameof(this.Vec)}: {this.Vec}, {nameof(this.Point)}: {this.Point}, {nameof(this.OtherTest)}: {this.OtherTest}, {nameof(this.Dir)}: {this.Dir}";
}