我需要从 .NET 4 中使用 dynamic 关键字声明的对象中获取属性及其值的字典吗?似乎为此使用反射是行不通的。
例子:
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 = ???
在 ExpandoObject 的情况下,ExpandoObject 类实际上为其属性实现了 IDictionary<string, object>
,因此解决方案与强制转换一样简单:
IDictionary<string, object> propertyValues = (IDictionary<string, object>)s;
请注意,这不适用于一般动态对象。在这些情况下,您需要通过 IDynamicMetaObjectProvider 下拉到 DLR。
有几种情况需要考虑。首先,您需要检查对象的类型。为此,您可以简单地调用 GetType()。如果该类型没有实现 IDynamicMetaObjectProvider,那么您可以使用与任何其他对象相同的反射。就像是:
var propertyInfo = test.GetType().GetProperties();
但是,对于 IDynamicMetaObjectProvider 实现,简单的反射不起作用。基本上,您需要了解更多有关此对象的信息。如果是 ExpandoObject(这是 IDynamicMetaObjectProvider 实现之一),您可以使用 itowlson 提供的答案。 ExpandoObject 将其属性存储在字典中,您可以简单地将动态对象转换为字典。
如果它是 DynamicObject(另一个 IDynamicMetaObjectProvider 实现),那么您需要使用此 DynamicObject 公开的任何方法。 DynamicObject 不需要在任何地方实际“存储”其属性列表。例如,它可能会执行以下操作(我正在重用 my blog post 中的示例):
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".
因此,您没有任何需要反映的内容 - 该对象没有任何属性,同时所有有效的属性名称都可以使用。
我想说对于 IDynamicMetaObjectProvider 实现,您需要过滤已知的实现,您可以在其中获取属性列表,例如 ExpandoObject,其余部分忽略(或抛出异常)。
如果 IDynamicMetaObjectProvider 可以提供动态成员名称,则可以获取它们。请参阅 apache 许可 PCL 库 Dynamitey(可在 nuget 中找到)中的 GetMemberNames 实现,它适用于实现 GetDynamicMemberNames
的 ExpandoObject
和 DynamicObject
以及提供元数据的任何其他 IDynamicMetaObjectProvider
具有 GetDynamicMemberNames
实现的对象,没有超出 is IDynamicMetaObjectProvider
的自定义测试。
在获取成员名称之后,要以正确的方式获取值需要做更多的工作,但 Impromptu 会这样做,但很难仅指出有趣的部分并使其有意义。这是 documentation,它与反射相同或更快,但是,它不太可能比 expando 的字典查找更快,但它适用于任何对象,expando、动态或原始 - 你可以命名它。
需要 Newtonsoft Json.Net
有点晚了,但我想出了这个。它只为您提供键,然后您可以在动态中使用它们:
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 :
foreach(string propertyName in GetPropertyKeysForDynamic(dynamicToGetPropertiesFor))
{
dynamic/object/string propertyValue = dynamicToGetPropertiesFor[propertyName];
// And
dynamicToGetPropertiesFor[propertyName] = "Your Value"; // Or an object value
}
选择以字符串或其他对象的形式获取值,或者执行另一个动态并再次使用查找。
JObject attributesAsJObject = dynamicToGetPropertiesFor;
替换为:var jObject = (JObject) JToken.FromObject(dynamicToGetPropertiesFor);
。此时,您可以通过执行 var objProperties = jObject.ToObject<Dictionary<string, object>>();
之类的操作来获取属性名称和值的字典。有了它,您就可以参加比赛了。这不需要动态。它适用于 DynamicObject
的任何子类
仅反映 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)))
{
}
不定期副业成功案例分享