[C#] 文字列でプロパティ名を指定してアクセス(参照・更新)する方法

    C#では、System.Reflection.PropertyInfoクラスのメソッドを利用して、プロパティ情報の参照や更新ができます。PropertyInfoクラスは、System.Type クラスの GetPropertyメソッドで取得できます。

    例えば次のような Person クラスがあるとします。

class Person
{
   // プロパティ
   public int Age { get; set; }
   public string Name { get; set; }

   // コンストラクタ
   public Person(string name, int age)
   {
       this.Name = name;
       this.Age = age;
   }

   // メソッド
   public void DebugPrint()
   {
       Console.WriteLine($"Name: {Name}, Age: {Age}");
   }
}

    Person クラスのプロパティをすべて取得したい場合、GetProperties メソッドで、Public なプロパティ情報を全件(PropertyInfo[])取得できます。以下のコードでは、プロパティ名を列挙しています。

// 型情報からプロパティ情報を取得
foreach (var item in typeof(Person).GetProperties())
{
   // プロパティ名を表示
   Console.WriteLine(item.Name);
}

インスタンスからプロパティの値を取得する

   インスタンスからプロパティ名を文字列で指定して動的に値を取得するには、PropertyInfoクラスの GetValue メソッドを使用します。以下のコードでは全プロパティの名前と値を列挙しています。

// インスタンスからプロパティ名と値を取得
var person = new Person("太郎", 30);
foreach (var item in person.GetType().GetProperties())
{
   // プロパティ名を表示
   Console.WriteLine($"{item.Name}: {item.GetValue(person)}");
}

インスタンス内のプロパティの値を更新する

   GetValueメソッドがあれば当然 SetValue メソッドも存在します。これを使えばプロパティ名を文字列で指定して、そのプロパティの値を更新することができます。たとえ readonly だろうと更新できてしまうので注意が必要です。以下のコードでは Age プロパティを変更しています。

// プロパティ名を指定して値を変更(privateでも変更可能)
var person = new Person("太郎", 30);
Console.WriteLine($"変更前 Age: {person.Age}");

// Ageプロパティのプロパティ情報から値を更新
var ageProperty = typeof(Person).GetProperty("Age");
ageProperty.SetValue(person, 100);
Console.WriteLine($"変更後 Age: {person.Age}");

dynamic型を使う

   C#は静的型付け言語ですが、dynamic型を使用することで、Javascript等の動的型付け言語のようにデータを扱うことが可能です。次のコードでは Person型のインスタンスを dynamic型の変数に入れて Age プロパティを参照・更新しています。

// dynamic型にして更新(privateの領域では変更不可)
var person = new Person("太郎", 30);
dynamic d = person;

// 以下の Ageプロパティの存在は実行時にしらべられる
d.Age = 50;
Console.WriteLine($"dynamic変更後 Age: {person.Age}");

   Ageという名前のメンバを持っているかどうか実行時に調べるので中身の型を問いません。つまり同じ名前のメンバがいれば異なる型でも同じようにふるまわせることができます。

サンプルコード

以上のコードをまとめたサンプルを以下にまとめます。

using System;

public class Program
{
    static void Main(string[] args)
    {
        // 型情報からプロパティ情報を取得
        foreach (var item in typeof(Person).GetProperties())
        {
            // プロパティ名を表示
            Console.WriteLine(item.Name);
        }

        // インスタンスからプロパティ名と値を取得
        var person = new Person("太郎", 30);
        foreach (var item in person.GetType().GetProperties())
        {
            // プロパティ名を表示
            Console.WriteLine($"{item.Name}: {item.GetValue(person)}");
        }

        // プロパティ名を指定して値を変更(privateでも変更可能)
        Console.WriteLine($"変更前 Age: {person.Age}");
        var ageProperty = typeof(Person).GetProperty("Age");
        ageProperty.SetValue(person, 100);
        Console.WriteLine($"変更後 Age: {person.Age}");

        // dynamic型にして更新(privateの領域では変更不可)
        dynamic d = person;
        d.Age = 50;
        Console.WriteLine($"dynamic変更後 Age: {person.Age}");
    }
   
    class Person
    {
        // プロパティ
        public int Age { get; set; }
        public string Name { get; set; }

        // コンストラクタ
        public Person(string name, int age)
        {
            this.Name = name;
            this.Age = age;
        }

        // メソッド
        public void DebugPrint()
        {
            Console.WriteLine($"Name: {Name}, Age: {Age}");
        }
    }
}