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

Tra*_*rks 16 c# dictionary properties dynamic

我希望能够使用属性的名称作为键来访问像字典这样的对象中的属性值.我真的不在乎这些值是作为对象返回的,所以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
Run Code Online (Sandbox Code Playgroud)

我本来要为此实现我自己的类,但后来我开始注意像DynamicObject这样的类实现了IDictionary接口,这让我觉得这已经在某个地方为我做了.

我想要的是类似于ASP.NET MVC使用的功能,允许使用匿名类型来设置HTML标记属性.我有很多使用字典作为数据源的类,但大多数时候我也应该能够传入对象.

因为这是一个通用,我想我会创建一个可重用的类,只使用IDictionary接口装饰一个对象.它将使我免于造成过载的爆炸.

Jar*_*Par 19

我不相信.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;
  }
}
Run Code Online (Sandbox Code Playgroud)

您可以使用它来包装任何类型,并使用索引器和名称语法来获取属性

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
Run Code Online (Sandbox Code Playgroud)


naw*_*fal 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;
}
Run Code Online (Sandbox Code Playgroud)

现在你可以这样做:

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

注意:

  1. 这个字典区分大小写(你可以通过右边简单地扩展它StringComparer).

  2. 它忽略了索引器(也是属性),但是你可以自己动手.

  3. 该方法不是通用的,因为它不会帮助装箱,因为它内部调用obj.GetType,所以它在那时无论如何都是盒子.

  4. 您只获得"可读"属性(否则您不会获得其中的值).既然你希望它也是"可写的"那么你也应该使用CanWriteflag.