C# 如何在动态对象的成员上进行反射?

C# 如何在动态对象的成员上进行反射?,c#,dynamic,reflection,C#,Dynamic,Reflection,我需要从.NET4中使用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> propertyValue

我需要从.NET4中使用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 = ???
dynamic s=newexpandoobject();
s、 Path=“/Home”;
s、 Name=“Home”;
//如何枚举路径和名称属性并获取它们的值?
IDictionary属性值=???

对于ExpandoObject,ExpandoObject类实际上为其属性实现了
IDictionary
,因此解决方案与转换一样简单:

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

请注意,这不适用于常规动态对象。在这些情况下,您将需要通过IDyNAMICMeta Objut提供程序下拉到DLR。

有几种情况需要考虑。 首先,您需要检查对象的类型。您只需为此调用GetType()。 如果该类型未实现IDynamicMetaObjectProvider,则可以使用与任何其他对象相同的反射。比如:

var propertyInfo = test.GetType().GetProperties();
但是,对于IDynamicMetaObjectProvider实现,简单反射不起作用。基本上,你需要更多地了解这个对象。如果是ExpandoObject(它是IDynamicMetaObjectProvider实现之一),则可以使用itowlson提供的答案。ExpandoObject将其属性存储在字典中,您可以简单地将动态对象强制转换到字典中

如果是DynamicObject(另一个IDynamicMetaObjectProvider实现),则需要使用此DynamicObject公开的任何方法。DynamicObject实际上不需要在任何地方“存储”其属性列表。例如,它可能会这样做(我正在重用来自的一个示例):

在本例中,无论何时尝试访问属性(使用任何给定名称),对象都将以字符串形式返回属性名称

dynamic obj = new SampleObject();
Console.WriteLine(obj.SampleProperty);
//Prints "SampleProperty".
因此,您没有任何需要反映的内容-此对象没有任何属性,同时所有有效的属性名称都可以使用


我想说,对于IDynamicMetaObjectProvider实现,您需要过滤已知的实现,在这些实现中,您可以获得属性列表,如ExpandooObject,其余的则忽略(或抛出异常)。

如果IDynamicMetaObjectProvider可以提供动态成员名称,您可以获得它们。请参阅apache许可PCL库中的实现(可在nuget中找到),它适用于
ExpandoObject
s和
dynamicmembernames
实现的
GetDynamicMemberNames
s,以及任何其他
IDynamicMetaObjectProvider
为元对象提供
GetDynamicMemberNames
实现而不进行自定义测试的
是IDynamicMetaObjectProvider


在获得成员名称后,要以正确的方式获得值需要做更多的工作,但即兴会做到这一点,但很难仅指出有趣的部分并使其有意义。这是一个,它与反射相同或更快,但不太可能比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;
}

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

谢谢您的帮助,不幸的是,示例有点过于简单。我需要能够在不知道动态对象的真实类型的情况下检查它。这只适用于ExpandooObject类的对象,DynamicObject类是另一个可扩展类,它不实现IDictionary,而是实现IDynamicMetaObjectProvider。但它确实回答了OP的问题。在我看来,如果我使用的类型是动态的,那么我就不应该对它的基础类型进行假设。我应该能够调用GetDynamicMemberNames来获取成员列表。静态类型比动态类型具有更好的运行时检查支持,这似乎很愚蠢!可以重写动态对象的GetDynamicMemberNames()方法,以返回动态成员的列表名称。问题是不能保证每个动态对象都有此方法(ExpandooObject没有)。反射对静态类型的效果更好,这并不奇怪。它最初是为他们创建的。对于dynamics,您必须更多地依赖于单元测试和TDD。GetDynamicMemberNames()的MSDN文档中提到:“此方法仅用于调试目的。”,这并不是很令人欣慰:(由于直截了当,代码是:var tTarget=target as IDynamicMetaObjectProvider;if(tTarget!=null){tList.AddRange(tTarget.GetMetaObject(Expression.Constant(tTarget)).GetDynamicMemberNames();}感谢您的优秀库。我在将动态对象往返到此库时遇到问题,并且能够使用您的库对其进行扩展。请举例说明。您不需要返回列表。太好了!我必须将JObject attributesAsJObject=DynamicToGetProperties for;更改为object attributesAsJObject=(JObject)JToken.FromObject(obj);虽然!!只是为了重申@k25所说的。您需要将
JObject attributesAsJObject=dynamicToGetPropertiesFor;
替换为如下内容:
var JObject=(JObject)JToken.FromObject(dynamicToGetPropertiesFor)此时,您可以通过执行类似于
var objProperties=jObject.ToObject();
的操作来获取属性名称和值的字典。
。有了它,您就可以开始比赛了。这不需要动态。它可以很好地处理
DynamicObject
的子类
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
}