2012-03-11 47 views
14

我希望能夠像字典一樣使用屬性名稱作爲關鍵字來訪問對象中的屬性值。我真的不在乎值是否作爲對象返回,所以Dictionary<string, object>沒問題。這是預期用途:在C中處理對象像屬性字典#

object person = new { Name: "Bob", Age: 45 }; 
IDictionary<string, object> lookup = new PropertyDictionary(person); 
string name = (string)person["Name"]; 
person["Age"] = (int)person["Age"] + 1; // potentially editable 

我正要實現我自己的類本,但後來我開始注意到像DynamicObject類實現IDictionary接口,這讓覺得這個已經正在爲我做的地方。

我想要的與ASP.NET MVC使用的功能類似,允許使用匿名類型來設置HTML標籤屬性。我有很多使用字典作爲數據源的類,但大多數時候我也應該能夠傳入對象。

因爲這是一個通用的library,我想我會創建一個可重用的類,它簡單地用IDictionary接口裝飾一個對象。它可以幫助我避免造成過載的爆炸。

+0

喜歡的東西在MSDN索引... http://msdn.microsoft.com/en-us/library/6x16t2tx.aspx – Lloyd 2012-03-11 04:59:07

回答

18

我不相信有一個內置在.NET Framework中已經.NET類型是這樣的。看起來你真的想要創建一個類似JavaScript對象的對象。如果是這樣,那麼從DynamicObject派生可能是正確的選擇。它允許您創建一個對象,當用dynamic包裝時,允許您直接綁定obj.Name或通過索引器obj["Name"]綁定。

public class PropertyBag : DynamicObject { 
    private object _source; 
    public PropertyBag(object source) { 
    _source = source; 
    } 
    public object GetProperty(string name) { 
    var type = _source.GetType(); 
    var property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); 
    return property.GetValue(_source, null); 
    } 
    public override bool TryGetMember(GetMemberBinder binder, out object result) { 
    result = GetProperty(binder.Name); 
    return true; 
    } 
    public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) { 
    result = GetProperty((string)indexes[0]); 
    return true; 
    } 
} 

你可以用它來包裝任何類型和同時使用索引和名稱的語法來獲取屬性

var student = new Student() { FirstName = "John", LastName = "Doe" }; 
dynamic bag = new PropertyBag(student); 
Console.WriteLine(bag["FirstName"]); // Prints: John 
Console.WriteLine(bag.FirstName);  // Prints: John 
+0

我做了類似的事情,但沒有繼承DynamicObject。我只是繼承了IDictionary,並且只支持索引,因爲這是我所需要的。 – 2012-03-11 06:59:01

+0

你看過ExpandoObject嗎? http://msdn.microsoft.com/en-us/library/system.dynamic.expandoobject.aspx – Scott 2012-03-11 07:01:06

+1

ExpandoObject只適用於從頭開始。 – 2012-03-12 02:34:34

1

動態關鍵字可能是您的一個選擇。它使用動態語言運行庫。在運行時,它會嘗試匹配程序中最接近的可用類型。如果它不能,那麼它將動態類型轉換爲dictionay對象,其中key是屬性的名稱,value是屬性的值。

遵循MSDN的這些鏈接:

Using dynamic keyword in C#
dynamic (C# Reference)
DLR Overview
usage of dynamic sample walkthough page

+0

唯一的問題是,我需要修改我的所有實現接受一個動態的。另外,我不知道如何按名稱引用屬性,因爲obj [「Name」]將被解釋爲對動態索引器的調用。 – 2012-03-11 05:19:30

+0

你不能直接去找字典嗎?有你自己的實現可能會讓事情搞砸了......我的觀點是你想要一個通過索引器自動轉換爲字典的類?你有沒有嘗試創建索引器的參數類型爲字符串? – Uday0119 2012-03-11 05:32:05

+0

我想包裝一個對象,而不是將它複製到一個字典。這個想法是傳遞一個對象,其中需要一個IDictionary。這樣我就可以在需要字典的地方使用匿名類型。 – 2012-03-11 05:46:45

8

我有這樣的擴展方法,可能是最簡單也可以得到:

public static Dictionary<string, object> ToPropertyDictionary(this object obj) 
{ 
    var dictionary = new Dictionary<string, object>(); 
    foreach (var propertyInfo in obj.GetType().GetProperties()) 
     if (propertyInfo.CanRead && propertyInfo.GetIndexParameters().Length == 0) 
      dictionary[propertyInfo.Name] = propertyInfo.GetValue(obj, null); 
    return dictionary; 
} 

現在你可以這樣做:

object person = new { Name = "Bob", Age = 45 }; 
var lookup = person.ToPropertyDictionary(); 
string name = (string)lookup["Name"]; 
lookup["Age"] = (int)lookup["Age"] + 1; // indeed editable 

注:

  1. 這本字典是區分大小寫的(你可以平凡擴展它傳遞正確的StringComparer)。

  2. 它忽略索引器(這也是屬性),但是由您來處理它。

  3. 該方法不是通用的,因爲它不會幫助拳擊,因爲它在內部調用obj.GetType,所以它在這一點上裝箱。

  4. 你得到的只是「可讀性」的屬性(否則你不會得到它的值)。 既然你希望它是「可寫的」,那麼你也應該使用CanWrite標誌。