名前で動的にプロパティにアクセスする

下の例の2行目のようにプロパティ名で任意のオブジェクトのプロパティに「簡単に」アクセスしたいと思いました。

var value1 = hoge.Aaa;
var value2 = hoge["Aaa"];
Assert.AreEqual(value1, value2);

最初、dynamicを使えばすぐできるのかと思ったら無理でした(hogeをdynamicにしてhoge["Aaa"]としたらインデクサにアクセスしてしまいます)。[]でなくていいから、dynamicと組み合わせて名前でプロパティにアクセスできる構文があればいいのにと思います。


代替案としてはラッパーを作ることかなぁ。たとえばこんなクラスを作ります。

public class InstancePropertyAccessor
{
    private readonly object _instance;

    private readonly Type _type;

    public InstancePropertyAccessor(object instance)
    {
        if (instance == null)
        {
            throw new ArgumentNullException("instance");
        }
        _instance = instance;
        _type = instance.GetType();
    }

    public object this[string propertyName]
    {
        get
        {
            var property = GetPropertyInfo(propertyName);
            return property.GetValue(_instance, null);
        }
        set
        {
            var property = GetPropertyInfo(propertyName);
            property.SetValue(_instance, value, null);
        }
    }

    private PropertyInfo GetPropertyInfo(string propertyName)
    {
        return _type.GetProperty(propertyName,
                                 BindingFlags.GetProperty |
                                 BindingFlags.SetProperty |
                                 BindingFlags.Public |
                                 BindingFlags.Instance);
    }
}

使用例はこんなです。

[TestClass]
public class InstancePropertyAccessorTest
{
    [TestMethod]
    public void TestMethod1()
    {
        var hoge = new Hoge {Aaa = "hoge", Bbb = 10};
        var accessor = new InstancePropertyAccessor(hoge);
        Assert.AreEqual("hoge", accessor["Aaa"]);
        Assert.AreEqual(10, accessor["Bbb"]);

        accessor["Aaa"] = "foo";
        accessor["Bbb"] = 20;
        Assert.AreEqual("foo", accessor["Aaa"]);
        Assert.AreEqual(20, accessor["Bbb"]);
    }
}

public class Hoge
{
    public string Aaa
    {
        get;
        set;
    }

    public int Bbb
    {
        get;
        set;
    }
}

この例ではリテラルでプロパティ名を指定していますが、実際のプログラムで使うときはプロパティ名を格納した変数を指定することになると思います。

ほんとうは accessor["Aaa"] ではなく hoge["Aaa"] としたいところですが、仕方ないですね。。。