外部ファイル(CSVや設定ファイル)から読み込んだデータや、動的に決定されるキー名に基づいて、オブジェクトのプロパティに値をセットしたい場合、リフレクションの SetValue メソッドが役立ちます。
これにより、コンパイル時にはプロパティ名が不明であっても、実行時に文字列でプロパティを指定して値を書き込むことが可能になります。
目次
プロパティ値の動的設定の実装
以下のサンプルコードでは、アプリケーションの設定クラス(AppConfiguration)に対し、キー(プロパティ名)と値のペアを指定してデータを流し込む処理を実装しています。
サンプルコード
using System;
using System.Reflection;
public class Program
{
public static void Main()
{
// 1. 値を設定したい対象のインスタンス生成
var config = new AppConfiguration();
Console.WriteLine("--- 設定前の状態 ---");
Console.WriteLine(config);
// 2. リフレクションを使って値を設定
// 通常の代入: config.Resolution = "1920x1080";
SetDynamicProperty(config, "Resolution", "1920x1080");
SetDynamicProperty(config, "MaxFrameRate", 60);
SetDynamicProperty(config, "EnableShadows", true);
// 存在しないプロパティ名を指定した場合のテスト
SetDynamicProperty(config, "UnknownSetting", 123);
Console.WriteLine("\n--- 設定後の状態 ---");
Console.WriteLine(config);
}
/// <summary>
/// 指定されたオブジェクトのプロパティに値を設定する
/// </summary>
/// <param name="target">対象オブジェクト</param>
/// <param name="propertyName">プロパティ名</param>
/// <param name="newValue">設定する値</param>
public static void SetDynamicProperty(object target, string propertyName, object newValue)
{
if (target == null) return;
// 1. オブジェクトの型情報を取得
Type type = target.GetType();
// 2. 指定された名前のプロパティ情報を取得
PropertyInfo propInfo = type.GetProperty(propertyName);
// プロパティが存在しない場合は処理を中断
if (propInfo == null)
{
Console.WriteLine($"[警告] プロパティ '{propertyName}' は存在しません。");
return;
}
// 3. 書き込み可能かチェック(setterが存在するか)
if (!propInfo.CanWrite)
{
Console.WriteLine($"[警告] プロパティ '{propertyName}' は書き込み不可です。");
return;
}
try
{
// 4. 値を設定
// 第1引数: 対象のインスタンス, 第2引数: セットする値, 第3引数: インデックス(通常はnull)
propInfo.SetValue(target, newValue);
Console.WriteLine($"[成功] {propertyName} に {newValue} を設定しました。");
}
catch (ArgumentException)
{
Console.WriteLine($"[エラー] {propertyName} への値の設定に失敗しました(型の不一致など)。");
}
}
}
// アプリケーション設定クラス
public class AppConfiguration
{
public string Resolution { get; set; } = "800x600"; // 解像度
public int MaxFrameRate { get; set; } = 30; // フレームレート
public bool EnableShadows { get; set; } = false; // 影の有効化
public override string ToString()
{
return $"[設定] 解像度:{Resolution}, FPS:{MaxFrameRate}, 影:{EnableShadows}";
}
}
解説と技術的なポイント
1. PropertyInfo.SetValueメソッド
GetProperty で取得した PropertyInfo オブジェクトの SetValue メソッドを使用することで、対象インスタンスのセッターを呼び出すことができます。
- 引数構成:
SetValue(object obj, object value)が基本形です。インデックス付きプロパティの場合は第3引数を指定します。 - 型の整合性: 渡す
valueの型は、プロパティの型と互換性がなければなりません。例えばint型のプロパティにstringを渡そうとするとArgumentExceptionが発生します(自動的な型変換は行われません)。
2. CanWriteプロパティによるチェック
プロパティには get アクセサのみ(読み取り専用)の場合があります。SetValue を呼ぶ前に propInfo.CanWrite をチェックすることで、書き込み不可能なプロパティへのアクセスによるエラーを回避できます。
3. 実用例:データマッパー
この技術は、データベースのクエリ結果(列名と値)をクラスのプロパティにマッピングしたり、JSONやXMLなどのテキストデータをオブジェクトに変換したりする「データバインディング」や「O/Rマッパー」の内部実装で頻繁に使用されています。
