像C#中的属性字典一样处理对象

时间:2012-03-11 04:51:52

标签: c# dynamic dictionary properties

我希望能够使用属性的名称作为键来访问像字典这样的对象中的属性值。我不关心值是否作为对象返回,因此Dictionary<string, object>很好。这是预期用途:

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接口装饰一个对象。它将使我免于造成过载的爆炸。

3 个答案:

答案 0 :(得分:18)

我不相信.Net框架中已经存在这样的内置.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

答案 1 :(得分: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标记。

答案 2 :(得分:1)

动态关键字可能是您的唯一选择。它使用动态语言运行时。在运行时,它会尝试匹配程序中最接近的可用类型。如果它不能,那么它将动态类型转换为dictionay对象,其中key是property的名称,value是property的值。

按照MSDN的这些链接:

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