web-dev-qa-db-ja.com

実行時にC#プロパティを動的に追加する

私はこれに対処するいくつかの質問があることを知っていますが、答えは通常、辞書またはパラメーターのコレクションを推奨するという線に沿っています。これは私の状況では機能しません。

リフレクションを介して機能するライブラリを使用して、プロパティを持つオブジェクトで多くの巧妙なことを行います。これは、定義済みクラスと動的クラスで機能します。私はこれをさらに一歩進め、これらの線に沿って何かをする必要があります:

public static object GetDynamicObject(Dictionary<string,object> properties) {
    var myObject = new object();
    foreach (var property in properties) {
        //This next line obviously doesn't work... 
        myObject.AddProperty(property.Key,property.Value);
    }
    return myObject;
}

public void Main() {
    var properties = new Dictionary<string,object>();
    properties.Add("Property1",aCustomClassInstance);
    properties.Add("Property2","TestString2");

    var myObject = GetDynamicObject(properties);

    //Then use them like this (or rather the plug in uses them through reflection)
    var customClass = myObject.Property1;
    var myString = myObject.Property2;

}

このライブラリは、プロパティが手動で割り当てられた動的変数タイプで正常に機能します。ただし、事前に追加されるプロパティの数やプロパティはわかりません。

76
Paul Grimshaw

ExpandoObjectをご覧になりましたか?

参照: http://blogs.msdn.com/b/csharpfaq/archive/2009/10/01/dynamic-in-c-4-0-introducing-the-expandoobject.aspx

MSDNから:

ExpandoObjectクラスを使用すると、実行時にインスタンスのメンバーを追加および削除したり、これらのメンバーの値を設定および取得したりできます。このクラスは動的バインディングをサポートします。これにより、sampleObject.GetAttribute( "sampleMember")のようなより複雑な構文の代わりに、sampleObject.sampleMemberのような標準構文を使用できます。

次のようなクールなことができます。

dynamic dynObject = new ExpandoObject();
dynObject.SomeDynamicProperty = "Hello!";
dynObject.SomeDynamicAction = (msg) =>
    {
        Console.WriteLine(msg);
    };

dynObject.SomeDynamicAction(dynObject.SomeDynamicProperty);

実際のコードに基づいて、次のことに興味があるかもしれません。

public static dynamic GetDynamicObject(Dictionary<string, object> properties)
{
    return new MyDynObject(properties);
}

public sealed class MyDynObject : DynamicObject
{
    private readonly Dictionary<string, object> _properties;

    public MyDynObject(Dictionary<string, object> properties)
    {
        _properties = properties;
    }

    public override IEnumerable<string> GetDynamicMemberNames()
    {
        return _properties.Keys;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        if (_properties.ContainsKey(binder.Name))
        {
            result = _properties[binder.Name];
            return true;
        }
        else
        {
            result = null;
            return false;
        }
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        if (_properties.ContainsKey(binder.Name))
        {
            _properties[binder.Name] = value;
            return true;
        }
        else
        {
            return false;
        }
    }
}

必要なのは次のとおりです。

var dyn = GetDynamicObject(new Dictionary<string, object>()
    {
        {"prop1", 12},
    });

Console.WriteLine(dyn.prop1);
dyn.prop1 = 150;

DynamicObjectから派生すると、これらの動的メンバーリクエストを処理するための独自の戦略を考え出すことができますここにモンスターがあることに注意してください:コンパイラはnot動的な呼び出しの多くを検証できるようにすると、インテリセンスが得られないので、覚えておいてください。

90
Clint

すばらしい答えをくれた@Clintに感謝します。

Expandoオブジェクトを使用してこれを簡単に解決できることを強調したかっただけです。

    var dynamicObject = new ExpandoObject() as IDictionary<string, Object>;
    foreach (var property in properties) {
        dynamicObject.Add(property.Key,property.Value);
    }
31
Paul Grimshaw