循环遍历 DynamicObject 属性。

46

我正在尝试理解DynamicObject类型。发现这篇MSDN文章非常简明清晰,说明了如何创建和使用DynamicObject:

http://msdn.microsoft.com/en-us/library/system.dynamic.dynamicobject.aspx

本文包含一个简单的DynamicDictionary类,该类继承自DynamicObject。
现在我想遍历动态创建的DynamicObject属性:
dynamic d = new DynamicDictionary();
d.Name = "Myname";
d.Number = 1080;

foreach (var prop in d.GetType().GetProperties())
{
  Console.Write prop.Key;
  Console.Write prop.Value;
}

显然这样做是不行的。我想学习如何在不改变我的DynamicDictionary类的情况下实现这一点,因为我真的想学习如何将其用于从DynamicObject继承的所有现有对象。

需要反射吗?我一定漏掉了什么...

3个回答

53

我相信你会对ExpandoObject类感兴趣。 DynamicObject类只是一个基类,你需要提供所有的逻辑。它明确实现了IDictionary<string, object>接口,因此你可以通过访问其属性或添加新属性来访问它。

// declare the ExpandoObject
dynamic expObj = new ExpandoObject();
expObj.Name = "MyName";
expObj.Number = 1000;

// print the dynamically added properties
foreach (KeyValuePair<string, object> kvp in expObj) // enumerating over it exposes the Properties and Values as a KeyValuePair
    Console.WriteLine("{0} = {1}", kvp.Key, kvp.Value);

// cast to an IDictionary<string, object>
IDictionary<string, object> expDict = expObj;

// add a new property via the dictionary reference
expDict["Foo"] = "Bar";

// verify it's been added on the original dynamic reference
Console.WriteLine(expObj.Foo);

我刚意识到您正在实现DynamicDictionary类,并误解了您的问题。对不起。

当与动态引用一起使用时,您只能访问公开公开的成员。由于除其他DynamicObject成员外,仅声明了Count为公共成员,因此如果您不打算进行任何进一步的更改,则需要使用反射才能访问内部字典以轻松获取这些值。


好的,谢谢。那么,对于一个继承DynamicObject并且不公开字典的现有对象来说,除了使用反射之外,我没有办法获取成员字典吗? - joeriks
据我所知,是的。您只能访问公共成员和DynamicObject类,其中成员访问是通过各种方法解析的。或者,您可以像ExpandoObject一样明确实现IDictionary<string, object>类,以使此过程更加容易。 - Jeff Mercado
抱歉,我一开始忽略了你的问题。我没有注意到你实际上正在实现示例代码。我在心里想,“没有DynamicDictionary类...” :) - Jeff Mercado
回答中没有回答问题的部分正是我所寻找的。 - Bovaz

14

看起来不错 - 但我不想/不能改变我的类,“GetDynamicMemberNames()”是一个可选的东西,即从DynamicObject继承的类可以覆盖它,但如果它不这样做,则调用基类中的函数,该函数返回一个空列表。 - joeriks
嗯,我明白了。那么我认为你要么需要使用ExpandoObject,要么需要自己实现它。 - Anuraj

0

我知道这个话题已经很老了,但对于那些仍在思考如何实现它的人来说,为什么不使用TryGetMember()方法,但构建一个继承GetMemberBinder的类呢?例如:

public class MyGetMemberBinder : GetMemberBinder
{
    public MyGetMemberBinder(string name, bool ignorecase) : base(name, ignorecase) { }
    public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion)=>throw new NotImplementedException();
}

然后使用LINQ:

Dictionary<string, object> AsStandardDictionary = DynamicDictionary.GetDynamicMemberNames().ToDictionary(x => x, y =>
{
    if(DynamicDictionary.TryGetMember(new MyGetMemberBinder(y, false), out var result))
        return result;
    else
        return null;
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接