2016-10-04 78 views
0

我想創建一個類層次結構,其中一個BaseClass.GetCopy()方法將提供相同的運行時子類的副本,具有相同的只讀ID屬性(通過構造函數傳遞),並與每一個公共可寫屬性複製。深層複製涉及參數的構造函數

我得到了下面的代碼,但測試沒有通過,因爲我不知道如何實現基於反射的特性複製。此外,在基類的構造函數成爲重複(錯誤傾向,IMO),並且已設置一個是公開的,這是不是在這種情況下,是一件好事,因爲我不希望客戶端代碼,可以設置IDS明確。

我的問題被表述爲在下面的代碼註釋:

[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; 
    } 
} 
+1

將您的類標記爲可序列化,您可以通過序列化和反序列化來創建深層副本。沒有其他代碼需要。 –

回答

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; 
}