我正在尝试创建一个类层次结构,其中BaseClass.GetCopy()
方法将提供相同运行时子类的副本,具有相同的readonly ID属性(通过构造函数传递),并且每个公共可写属性都被复制。
我得到了下面的代码,但测试没有通过,因为我不知道 如何实现基于反射的属性复制 。此外,基类中的构造函数变得重复(容易出错,IMO),参数化的构造函数是公共的,在这种情况下这不是一件好事,因为我不希望客户端代码能够设置明确地说。
我的问题在下面的代码中作为评论说明:
[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;
}
}
答案 0 :(得分:0)
我已经创建了一个可以满足您建议的方法。 我们的想法是迭代抛出对象中的所有字段并创建它的副本,这样您就可以进行测试评估。
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;
}