[英]Deep copy via reflection involving parameterized constructors
I am trying to create a class hierarchy where a BaseClass.GetCopy()
method would provide copies of the same runtime subclass, with the same readonly ID property (passed via constructor), and with every public writeable property copied. 我正在尝试创建一个类层次结构,其中
BaseClass.GetCopy()
方法将提供相同的运行时子类的副本,具有相同的只读ID属性(通过构造函数传递),并且复制了每个公共可写属性。
I got the code below, but the tests don't pass, since I didn't know how to implement reflection-based property copying . 我得到了下面的代码,但是测试没有通过,因为我不知道如何实现基于反射的属性复制 。 Also, the constructors in base class became duplicated (error-prone, IMO), and the parameterized one is public, which is not a good thing in this case, since I don't want the client code to be able to set Ids explicitly.
另外,基类中的构造函数被复制(容易出错,IMO),并且参数化的构造函数是公共的,在这种情况下这不是一件好事,因为我不希望客户端代码能够显式设置Ids 。
My questions are stated as comments in the code below: 我的问题在以下代码中以注释的形式陈述:
[TestFixture]
public class RepoItemTests
{
[Test]
public void CloneHasSameId()
{
var one = new ConcreteRepoItemName();
var two = one.GetCopy();
Assert.AreEqual(one.Id, two.Id);
}
[Test]
public void CloneIsSubclassInstance()
{
var one = new ConcreteRepoItemAge();
var two = one.GetCopy();
Assert.IsInstanceOf<ConcreteRepoItemAge>(two);
}
[Test]
public void ChangingCloneNameDoesntChangeOriginalAge()
{
var one = new ConcreteRepoItemName() { Name = "original" };
var two = one.GetCopy() as ConcreteRepoItemName;
Assert.AreEqual(one.Name, two.Name);
two.Name = "modified";
Assert.AreNotEqual(one.Name, two.Name);
}
[Test]
public void ChangingCloneAgeDoesntChangeOriginalAge()
{
var one = new ConcreteRepoItemAge() { Age = 22 };
var two = one.GetCopy() as ConcreteRepoItemAge;
Assert.AreEqual(one.Age, two.Age);
two.Age = 33;
Assert.AreNotEqual(one.Age, two.Age);
}
}
public class ConcreteRepoItemName : AbstractRepoItem<ConcreteRepoItemName>
{
public ConcreteRepoItemName() : base() { }
// I don't want the constructor below to be public
public ConcreteRepoItemName(Guid id) : base(id) { }
public string Name { get; set; }
}
public class ConcreteRepoItemAge : AbstractRepoItem<ConcreteRepoItemAge>
{
public ConcreteRepoItemAge() : base() { }
// I don't want the constructor below to be public
public ConcreteRepoItemAge(Guid id) : base(id) { }
public decimal Age { get; set; }
}
public abstract class AbstractRepoItem<T> where T : AbstractRepoItem<T>, new()
{
public AbstractRepoItem()
{
Id = Guid.NewGuid();
}
// I don't want the constructor below to be public
protected AbstractRepoItem(Guid id)
{
Id = id;
}
public Guid Id { get; private set; }
public T GetCopy()
{
var clone = Activator.CreateInstance(typeof(T), new object[] { Id }) as T;
/// HOW DO I COPY RUNTIME PROPERTIES HERE VIA REFLECTION?
return clone;
}
}
I have created a method that can serve your propose. 我创建了一种可以满足您的建议的方法。 The idea is to iterate throw all the fields in the object and create a copy of it that way you can make your evaluations for testing.
这个想法是迭代抛出对象中的所有字段并创建它的副本,这样您就可以对测试进行评估。
public static T Copy<T>(T obj)
{
if (obj == null) throw new ArgumentNullException("obj");
Type Typeobj = obj.GetType();
var ResultObj = Activator.CreateInstance(Typeobj);
Type ResultObjType = ResultObj.GetType();
foreach (var field in Typeobj.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance))
{
FieldInfo f = ResultObjType.GetField(field.Name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
f.SetValue(ResultObj, field.GetValue(obj));
}
return (T) ResultObj;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.