如何反映动态对象的成员?

中的 Dynamic 关键字声明的对象中获取属性及其值的字典。NET 4?似乎使用反射不会起作用。

例如:

dynamic s = new ExpandoObject();
s.Path = "/Home";
s.Name = "Home";


// How do I enumerate the Path and Name properties and get their values?
IDictionary<string, object> propertyValues = ???
121587 次浏览

对于 ExpandObject 来说,ExpandObject 类实际上为它的属性实现了 IDictionary<string, object>,因此解决方案就像转换一样简单:

IDictionary<string, object> propertyValues = (IDictionary<string, object>)s;

请注意,这不适用于一般的动态对象。在这些情况下,您需要通过 IDDynamicMetaObjectProvider 下拉到 DLR。

有几种情况需要考虑。 首先,您需要检查对象的类型。 如果该类型没有实现 IDDynamicMetaObjectProvider,那么您可以像对待其他任何对象一样使用反射:

var propertyInfo = test.GetType().GetProperties();

但是,对于 IDDynamicMetaObjectProvider 实现,简单反射不起作用。基本上,您需要更多地了解这个对象。如果它是 ExpendoObject (IDDynamicMetaObjectProvider 实现之一) ,则可以使用 itowlson 提供的答案。ExpandoObject 将其属性存储在一个 dictionary 中,您可以简单地将动态对象强制转换为 dictionary。

如果它是 DynamicObject (另一个 IDDynamicMetaObjectProvider 实现) ,那么您需要使用 DynamicObject 公开的任何方法。DynamicObject 实际上不需要在任何地方“存储”它的属性列表。例如,它可能会做这样的事情(我正在重用来自 我的博客文章的一个示例) :

public class SampleObject : DynamicObject
{
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = binder.Name;
return true;
}
}

在这种情况下,无论何时尝试访问属性(使用任何给定的名称) ,对象都只是以字符串的形式返回属性的名称。

dynamic obj = new SampleObject();
Console.WriteLine(obj.SampleProperty);
//Prints "SampleProperty".

因此,您没有任何要反映的内容-这个对象没有任何属性,同时所有有效的属性名都将正常工作。

我要说的是,对于 IDDynamicMetaObjectProvider 实现,您需要对已知的实现进行筛选,在这些实现中您可以获得一个属性列表,比如 ExpandObject,并忽略(或抛出一个异常)其余的属性。

如果 IDDynamicMetaObjectProvider 可以提供动态成员名称,则可以获取它们。参见在 apache 许可的 PCL 库 火药味十足中的 GetMemberNames实现(可以在 nuget 中找到) ,它适用于实现 GetDynamicMemberNamesExpandoObjectDynamicObject,以及任何其他提供 GetDynamicMemberNames实现的元对象的 IDynamicMetaObjectProvider,除了 is IDynamicMetaObjectProvider没有定制测试。

在获得成员名称之后,通过正确的方式获得值需要做更多的工作,但是即兴操作可以做到这一点,但是仅仅指向有趣的部分并使其有意义就比较困难了。这是 文件,它等于或快于反射,但是,不太可能比扩展的字典查找快,但是它适用于任何对象,扩展,动态或原始-你说它。

需要牛顿软件

有点晚了,但我想到了这个。它给你的只是键,然后你可以使用这些动态:

public List<string> GetPropertyKeysForDynamic(dynamic dynamicToGetPropertiesFor)
{
JObject attributesAsJObject = dynamicToGetPropertiesFor;
Dictionary<string, object> values = attributesAsJObject.ToObject<Dictionary<string, object>>();
List<string> toReturn = new List<string>();
foreach (string key in values.Keys)
{
toReturn.Add(key);
}
return toReturn;
}

然后你就这样说:

foreach(string propertyName in GetPropertyKeysForDynamic(dynamicToGetPropertiesFor))
{
dynamic/object/string propertyValue = dynamicToGetPropertiesFor[propertyName];
// And
dynamicToGetPropertiesFor[propertyName] = "Your Value"; // Or an object value
}

选择以字符串或其他对象的形式获取值,或者执行另一个动态操作并再次使用查找。

只反射 json 对象的简单解决方案:

using System.Collections.Generic;
using System.Text.Json;
dynamic d = new {a = 1, b = 2, c = 3};
foreach ((string k, object o) in JsonSerializer.Deserialize<Dictionary<string, object>>(JsonSerializer.Serialize(d)))
{


}