2013-04-04 27 views
54

我知道存在一些解決此問題的問題,但答案通常沿着推薦字典或參數集合的路線行事,這在我的情況下不起作用。在運行時動態添加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; 

} 

圖書館正常工作與動態變量類型,具有手動分配的屬性。但是我不知道預先添加了多少或什麼屬性。

回答

75

你看過ExpandoObject了嗎?

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

從MSDN:

的ExpandoObject類,可以添加在運行時刪除其實例的成員,還來設置和獲取這些成員的值。該類支持動態綁定,它使您可以使用標準語法(如sampleObject.sampleMember)而不是像sampleObject.GetAttribute(「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派生出來,您可以想出處理這些動態成員請求的自己的策略,請注意這裏有怪物:編譯器將而不是能夠驗證很多動態調用,而且您不會得到intellisense,所以請記住這一點。

17

感謝@Clint爲偉大的答案:

只想強調它是多麼容易此使用Expando的目的是解決:

public static dynamic GetDynamicObject(Dictionary<string,object> properties) { 
    var dynamicObject = new ExpandoObject() as IDictionary<string, Object>; 
    foreach (var property in properties) { 
     dynamicObject.Add(property.Key,property.Value); 
    } 
    return dynamicObject; 
} 
+6

+1。備註:爲什麼不返回字典而不是動態? (至少,IDictionary)?我的意思是,返回動態是有點「誤導」,因爲你總是會返回一個字典。 – Veverke 2015-04-20 15:35:48