.net column

.NET開発者のためのブログメディア

C#のリフレクションとは?|基本の使い方から紹介!

2020年07月03日
SE
C#のリフレクションってどのようなものですか?
PM
プログラムを開発する時に、プログラムの中身を反映させる時に使うものです。

リフレクションとは?

リフレクション(reflection)という言葉はどのような意味なのでしょうか。reflectionは、「投影、反映」という意味で、プログラム開発においては、プログラムの中身を反映させたい時に使います。

リフレクションはC#に限らず、Javaなどのオブジェクト指向言語で使用される言葉で、「クラスのメタ情報を取得する」と説明されます。具体的に言うと、リフレクションとはプログラムのクラスやそのメンバーの名前、フィールドの型などを知ることが出来る機能のことです。

この記事ではC#のリフレクションの機能と、具体的な使い方について解説します。是非参考にしてください。

C#のリフレクションの基本

説明より、まず実例を見てマスターしましょう。以下がC#のリフレクションサンプルです。

using System;
using System.Reflection;

namespace ConsoleApp1
{
class Human
{
String name;
public Human(String n)
{
name = n;
}
public void Eat(String food)
{
Console.WriteLine(name + “”は “” + food + “” を食べます。””);
}
}

class Program
{
static void Main(string[] args)
{
Type h_type = Type.GetType(“”ConsoleApp1.Human””);

if (h_type != null)
{
MethodInfo w_m = h_type.GetMethod(“”Eat””);

if (w_m != null)
{
var h = Activator.CreateInstance(h_type, new string[] { “”太郎”” });
w_m.Invoke(h, new String[] { “”昼食”” });
}
}
}
}
}

文字列で指定してクラスを実行する

上記の例にあるMainメソッド内で、Type.GetTypeによりHumanクラスの情報を取得しています。ここでは、””ネームスペース.クラス名””で指定する必要があります。

返り値がnullではなければHumanクラスが存在するので、次にGetMethodでEatというメソッドがあるかどうかを、GetMethodでチェックします。

GetMethodの戻り値がnullでなければ、Eatメソッドがあることになります。そこでActivator.CreateInstanceでHumanクラスを生成します。この時コンストラクタに””太郎””というパラメータを与えています。

そして生成したHumanクラスのインスタンスのEatメソッドを、Invokeで呼び出します。この時””昼食””と言うパラメータを渡しています。実行結果は以下になります。

太郎は 昼食 を食べます。

リフレクションは動作テストに役立つ

上のようなリフレクションは何に役立つのでしょうか。普通にHumanクラスを生成してEatメソッドを呼べばいいのではないか、と思う人もいるのではないでしょうか。実は、リフレクションは動作テストに役立つのです。

上のソースはHumanクラスに直接アクセスせずに、Humanクラスを生成してEatメソッドを実行しています。なので、文字列を入れ替えれば、他のクラスにも使用でき、使いまわすことが可能になります。これが動作テストを行うのに便利なのです。

リフレクションは通常は使用しない

何かバグがあった場合、ソースに直接デバッグ用のコードを書くと、後でそれを消し忘れて残ってしまうということが起こる可能性があります。しかし、リフレクションを使えば外部からノータッチで動作チェックができるのです。

逆に言えば、リフレクションは特殊な使い方をするもので、プログラムの中で普通に使用をするのは控えた方がよいでしょう。リフレクションは、C#のデバッガで処理を追うことが出来なくなる弊害もあります。あくまでも動作チェックをするために、テストコードだけで使用しましょう。

リフレクションはログ出力にも便利

リフレクションという考え方は、ログを出力する時も便利です。まず上のC#のサンプルの先頭に「using System.Diagnostics;」を記述してください。そしてHumanクラスのEatメソッドを以下のように変えます。

public void Eat(String food)
{
Program.LogDisp(this);
Console.WriteLine(name + “”は “” + food + “” を食べます。””);
}

そしてProgramクラスを以下のように変えます。

class Program
{
public static void LogDisp(object o)
{
StackFrame sf = new StackFrame(1); // 1つ前のスタックを取得
Console.WriteLine(o.GetType() + “” “” + sf.GetMethod());
}
static void Main(string[] args)
{
Human h = new Human(“”花子””);
h.Eat(“”夕食””);
}
}

元のソースをほとんど変更せずにクラス情報を取得できる

上のC#のプログラムを実行すると、以下のように表示されます。

ConsoleApp1.Human Void Eat(System.String)
花子は 夕食 を食べます。

HumanクラスにLogDispを1か所追加しましたが、クラスやメソッドの情報は外側のLogDispで取得し、表示しています。StackFrameによりLogDispを呼び、メソッド名を表示していることに注意してください。

元のプログラムにログ出力を追加するだけで、実行時に多くの情報を取得できるので、リフレクションはデバッグにとても役立つことが分かります。

リフレクションはプロパティのテストにも使える

プロパティを持つクラスのテストでも、リフレクションは役立ちます。下記にある、C#のサンプルをご覧ください。

using System;
using System.Reflection;

namespace ConsoleApp1
{
class ThreeValSum
{
public int Val1 { get; set; }
public int Val2 { get; set; }
public int Val3 { get; set; }

public int Sum()
{
return Val1 + Val2 + Val3;
}
}

class Program
{
static void Main(string[] args)
{
Type type = Type.GetType(“”ConsoleApp1.ThreeValSum””);

if (type!=null)
{
PropertyInfo[] pinfo_ary = type.GetProperties();
int len = pinfo_ary.Length;
Console.WriteLine(“”プロパティの数は”” + len);

var tvs = Activator.CreateInstance(type, null);

for (int i = 0; i < len; i++)
{
var ap = tvs.GetType().GetProperty(pinfo_ary[i].Name);
ap.SetValue(tvs, i+1);
Console.WriteLine(pinfo_ary[i].Name + “”に”” + i + “”を代入””);
}
MethodInfo s_m = type.GetMethod(“”Sum””);
var sum = s_m.Invoke(tvs, null);
Console.WriteLine(“”合計は””+sum);
}
}
}
}

リフレクションなら効率的にテストが可能

上のソースのTheeValSumは、3つのint型のプロパティを持ち、Sumメソッドでその3つの値を合計して返します。Mainメソッドでは、TheeValSumの全てのプロパティの情報をGetPropertiesで配列として取得しています。

TheeValSumをCreateInstanceで生成し、GetPropertyでプロパティの名前を指定して、SetValueで全てのプロパティに値を代入しています。最後にSumを呼び出して結果を表示します。実行結果は以下になります。

プロパティの数は3
Val1に0を代入
Val2に1を代入
Val3に2を代入
合計は6

SE
メソッドを書き換えることで、反映させることができるのですね。
PM
動作テストをするにはなくてはならない機能ですので、覚えておくといいでしょう。

リフレクションで効率良く動作テストをしよう

C#のリフレクションを紹介しましたが、いかがでしたでしょうか。リフレクションを使えばテスト対象のクラスを修正せず、効率よく動作確認を行えます。是非リフレクションをマスターし、品質の高いC#のプログラムを作ってください。


.NET分野でのキャリアアップをお考えの方は、現在募集中の求人情報をご覧ください。

求人一覧

また、直接のエントリーも受け付けております。

エントリー(応募フォーム)