親クラスのインスタンスが持っている全プロパティの値を子クラスに簡単にコピーできるようにしたい
何かしらのライブラリ等に存在するクラスにちょっとした拡張を加えた子クラスを用意して使う、という場面はたまにあります。
そういう場合、(使い方にもよりますが)既存のインスタンスにすでに持たれている各プロパティの値を子クラスにもコピーしたい、ということがあります。
そのような場面に直面した場合の手軽な対応方法を紹介します。
以下のようなクラスを例として説明します。
Parent.cs
// 親クラス
public class Parent
{
public int Prop1 { get; set; }
public string Prop2 { get; set; }
public object Prop3 { get; set; }
}
// 子クラス
public class Child : Parent
{
// 子クラスで付け足すプロパティ
public object OriginalProp { get; set; }
// 子クラスで付け足すメソッド
public void OriginalMethod()
{
// Do something
}
}
良くない方法(ゴリ押し実装)
以下のように、子クラスのコンストラクタで引数として親クラスのインスタンスを受け取り、プロパティを1つ1つ代入していく方法でも実現はできます。
ですが、この方法には以下のような問題があります。
- 親クラスがアップデートされてプロパティに変更が加えられる(またはプロパティが増える)たびに子クラスのメンテナンスが必要になる。
- プロパティの数が多いと実装が面倒。
Parent.cs
// 子クラス
public class Child : Parent
{
// 子クラスのコンストラクタ内でプロパティを1つ1つ代入させるように実装する。
public Child(Parent parent)
{
this.Prop1 = parent.Prop1;
this.Prop2 = parent.Prop2;
this.Prop3 = parent.Prop3;
}
/* 以下略 (独自に足したプロパティやメソッド) */
}
BusinessLogic.cs
// 子クラスを使用する業務ロジッククラス
public class BusinessLogic()
{
// このメソッドの中で子クラスを生成して使用する。
public void SomeMethod(Parent parent)
{
var child = new Child(parent);
// Do something
}
}
(多分)良い方法
子クラスのコンストラクタを以下のようにすることで、親クラスがメンテナンスされた場合でもそのまま動いてくれるようになります。
Parent.cs
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
// 子クラス
public class Child : Parent
{
public Child(Parent parent)
{
// 親クラスのプロパティ情報を一気に取得して使用する。
List<PropertyInfo> props = parent
.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)?
.ToList();
props.ForEach(prop =>
{
var propValue = prop.GetValue(parent);
typeof(Child).GetProperty(prop.Name).SetValue(this, propValue);
});
}
/* 以下略 (独自に足したプロパティやメソッド) */
}