オブジェクト指向だと値を格納する目的のクラスってよく使います。(例えば、社員クラスとか...)
で、それらのデータ格納用クラスのメンバ変数を一気に出力するのを汎用的にするというのが今回の目的です。
例えば下記のようなクラスがあるとします。
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime Birthday { get; set; }
public List FamilyNames { get; set; }
}
public class Car
{
public string CarName { get; set; }
public string Engine { get; set; }
public int DryWeight { get; set; }
public int HorsePower { get; set; }
}
汎用的(つまりどのクラスでも使えるよう動的)にするには下記のようにします。(汎用的でない例も入れてます)(C#)
private void button1_Click(object sender, EventArgs e)
{
//テストクラスのインスタンス生成(.Net 3.0以降で使えるクラス初期化の方法)
Person prs = new Person()
{
FirstName = "礼司",
LastName = "安部",
Birthday = new DateTime(1971, 10, 10),
FamilyNames = new List<string> { "安部優", "安部永太","ちび安部" }
};
Car car = new Car() {
CarName = "GT-R",
Engine = "VR38DETT",
DryWeight = 1740,
HorsePower = 480
};
Console.WriteLine("--------------汎用的でない出力の仕方--------------");
Console.WriteLine("FirstName 値 : " + prs.FirstName);
Console.WriteLine("LastName 値 : " + prs.LastName);
Console.WriteLine("Birthday 値 : " + prs.Birthday.ToString());
Console.Write("FamilyNames 値 : ");
foreach (string item in prs.FamilyNames)
{
Console.Write(item+",");
}
Console.WriteLine("\n\n--------------汎用的な出力の仕方--------------");
//prsオブジェクトのメンバと値を出力。typeof(型)を忘れずに。
OutputProperty(prs,typeof(Person));
//carオブジェクトのメンバと値を出力
OutputProperty(car, typeof(Car));
//prsオブジェクトのListの場合は下記のようにすればよろし
List<Person> lstp = new List<Person>();
lstp.Add(prs);
lstp.Add(new Person() { FirstName = "aaa", LastName = "bbb", Birthday = new DateTime(1971, 10, 10) });
lstp.Add(new Person() { FirstName = "ccc", LastName = "sss", Birthday = new DateTime(1971, 10, 10) });
Console.WriteLine("\n\n--------------汎用的な出力の仕方(List版)--------------");
//出力。ListをArrayListにすることが肝かな。
OutputPropertyArray(new ArrayList(lstp), typeof(Person));
}
/// <summary>
/// オブジェクトのメンバを取得しプロパティなら表示する。
/// </summary>
/// <param name="targetobj">クラスのインスタンス</param>
/// <param name="t">クラスのTypeオブジェクト</param>
private void OutputProperty(object targetobj, Type t)
{
//using System.Reflection;が必要
//メンバを取得する
MemberInfo[] members = t.GetMembers(
BindingFlags.Public |
BindingFlags.Instance |
BindingFlags.DeclaredOnly);
foreach (MemberInfo m in members)
{
//メンバの型と、名前を表示する
//メンバの型がプロパティなら
if (m.MemberType.ToString().Equals("Property"))
{
Console.WriteLine("メンバ型:{0} - メンバ名:{1}", m.MemberType, m.Name);
PropertyInfo pr = t.GetProperty(m.Name);
object resobj = pr.GetValue(targetobj, null);
//List<string>ならカンマ区切りで表示
if (resobj != null && typeof(List<string>).IsAssignableFrom(resobj.GetType()))
{
List<string> lstRes = (List<string>)resobj;
//LINQを使用してList<string>をカンマ区切りで結合する。(ループで回してもいいんだけどこっちの方がシンプルなんで...)
Console.WriteLine(" 値 : " + string.Join(", ", lstRes.ToArray()) );
}
else if (resobj != null)
{
Console.WriteLine(" 値 : " + resobj.ToString());
}
}
}
}
/// <summary>
/// Listコレクション
/// </summary>
/// <param name="targetobj">クラスのインスタンスのコレクション</param>
/// <param name="t">クラスのTypeオブジェクト</param>
private void OutputPropertyArray(ArrayList targetobj, Type t)
{
foreach (var item in targetobj)
{
OutputProperty(item, t);
}
}
オブジェクトのメンバの型情報を取得するには、クラスの Type 情報を取得し、GetMembers メソッドで取得できます。
この際、どこまでを含めるかのフラグの指定は、
MSDN:BindingFlags 列挙体 (System.Reflection)を使います。
メンバの値の取得は、プロパティの場合 Type.GetProperty("名前") で
PropertyInfo オブジェクトを取得し、
GetValue メソッドで可能です。
メソッドの場合は
MethodInfo 、フィールドの場合は
FieldInfo クラスを使えるようですね。
取得したプロパティの値が List
かどうかは、(.Net)objectがListかまたは配列かどうか判定する で詳しく書いています。
上記コードを実行した結果は下記のようになります。
--------------汎用的でない出力の仕方--------------
FirstName 値 : 礼司
LastName 値 : 安部
Birthday 値 : 1971/10/10 0:00:00
FamilyNames 値 : 安部優,安部永太,ちび安部,
--------------汎用的な出力の仕方--------------
メンバ型:Property - メンバ名:FirstName
値 : 礼司
メンバ型:Property - メンバ名:LastName
値 : 安部
メンバ型:Property - メンバ名:Birthday
値 : 1971/10/10 0:00:00
メンバ型:Property - メンバ名:FamilyNames
値 : 安部優, 安部永太, ちび安部
メンバ型:Property - メンバ名:CarName
値 : GT-R
メンバ型:Property - メンバ名:Engine
値 : VR38DETT
メンバ型:Property - メンバ名:DryWeight
値 : 1740
メンバ型:Property - メンバ名:HorsePower
値 : 480
--------------汎用的な出力の仕方(List版)--------------
メンバ型:Property - メンバ名:FirstName
値 : 礼司
メンバ型:Property - メンバ名:LastName
値 : 安部
メンバ型:Property - メンバ名:Birthday
値 : 1971/10/10 0:00:00
メンバ型:Property - メンバ名:FamilyNames
値 : 安部優, 安部永太, ちび安部
メンバ型:Property - メンバ名:FirstName
値 : aaa
メンバ型:Property - メンバ名:LastName
値 : bbb
メンバ型:Property - メンバ名:Birthday
値 : 1971/10/10 0:00:00
メンバ型:Property - メンバ名:FamilyNames
メンバ型:Property - メンバ名:FirstName
値 : ccc
メンバ型:Property - メンバ名:LastName
値 : sss
メンバ型:Property - メンバ名:Birthday
値 : 1971/10/10 0:00:00
メンバ型:Property - メンバ名:FamilyNames
プロジェクト内で扱うクラスの数が多くて、クラス内メンバの値が一気にほしい時などはこのようにリフレクションを使ってやると便利ですね。
参考:
dobon.net:型(クラス、構造体など)のすべてのメンバを取得する オブジェクトからメンバの型情報を取得する方法について解説されています。
dobon.net:型のメンバを動的に呼び出す オブジェクトのメンバの値を取得する方法です。今回はページ中ほどの「MethodInfo、ConstructorInfo、PropertyInfo、FieldInfoクラスを使用した方法」を使っています。