2016-10-04 7 views
0

メソッドが同じ実行時サブクラスのコピーを提供し、同じ読み取り専用IDプロパティ(コンストラクタ経由で渡される)を持ち、すべてのパブリック書き込み可能プロパティがコピーされるクラス階層を作成しようとしています。 。パラメータ化されたコンストラクタを使用したリフレクト経由のディープコピー

私は以下のコードを得たが、私はをコピーリフレクションベースのプロパティを実装する方法を知らなかったので、テストは、合格しません。また、基底クラスのコンストラクタが重複して(エラーが発生しやすく、IMO)、パラメータ化されたものがpublicになっています。クライアントコードがIdを明示的に設定できるようにしたくないので、この場合は良いことではありません。

私の質問は、以下のコード内のコメントとして記載されています

[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; 
} 
関連する問題