在expando对象上定义计算属性

时间:2013-02-11 16:28:18

标签: c# dynamic expandoobject

我正在使用expando对象,我正在尝试定义计算属性。

我知道我可以通过执行以下操作来定义一个简单的属性:

dynamic myExpando = new ExpandoObject();
myExpando.TheAnswerToLifeTheUniverseAndEverything= 42;

同样,我也可以定义一个方法:

myExpando.GetTheQuestion = ((Func<string>)(() =>
        {
            return "How many road must a man walk down before we can call him a man?";
        }));  

使用标准对象时,我们可以定义计算属性,即定义一个属性,该属性将返回自定义方法/ calc的结果。不需要一个例子。

我需要在我的expando上做类似的事情 - 拥有一个实际调用“Func”的属性(或者其他形式的委托,只要我可以调用自定义方法并且具有自定义返回类型,任何事情都会发生)。所以基本上我需要像第二个例子中那样调用一个方法,但它的作用就像一个属性。

基本上我需要能够使用 myExpando.GetTheQuestion 而不是 myExpando.GetTheQuestion()来调用它,同时保持定义自定义委托作为属性的能力体。

有办法做到这一点吗?我相信我可以通过使用表达式树来做到这一点,但我承认我在那里有点失落。任何人都可以提供一些如何实现这一目标的指导吗?


修改

做了更多的研究..除非有一些非常具体的类/接口/ sintax,我不知道我开始认为上述是不可能的。从我得到的,ExpandoObject类通过定义一些执行后台管道的方法 - TryGetMember,TrySetMember等来工作。 现在,在动态对象上“访问属性”时,TryGetMember是被调用的成员。该成员从一种内部字典返回一个值(是的,我知道......这有点简化,但应该给出这个想法)......没有对返回的值类型进行测试。这意味着在我的示例中 myExpando.GetTheQuestion 将返回原始Func。

看起来,由于TryGetMember只返回一个值,因此无法使其“执行”属性代码。要实现这一点,您需要某种表达式/ lambda / func / action代理,该值实际上是方法的结果。这似乎是不可能的(除非我错过了某些东西,否则也没有多大意义 - 基本上你会有一个设置为'委托'的值,然后作为委托返回值得到???)。我是正确的还是我还是错过了什么?

1 个答案:

答案 0 :(得分:2)

您需要通过继承DynamicObject并覆盖

来制作自己的ExpandoObject

public override bool TryGetMember(GetMemberBinder binder, out object result)public override bool TrySetMember(SetMemberBinder binder, object value)

实施TrySetMember以将值存储在Dictionary<string,object>下的私有binder.Name中,并使用TryGetMember从该字典中检索它,这将为您提供基本的ExpandoObject。然后为了给它提供你需要的功能,在拉动对象之后添加一个检查TryGetMember,看看它是否is Delagate然后使用反射来查看它是否不带任何参数。如果两者都为真,则转换为dynamic并且不添加arg调用括号并将其分配给result

public override bool TryGetMember(GetMemberBinder binder, out object result)
{
      if (_dictionary.TryGetValue(binder.Name, out result)){
           if(result is Delegate && /* some reflection check on args*/){
                result = ((dynamic)result)();
           }
      }
}

我有一个开源框架ImpromptuInterface(在nuget中)有一个非密封 ImpromptuDictionary,您可以将其作为ExpandoObject代替,特别是如果您需要ExpandoObject的任何更细微的特征,例如gui绑定支持。它还有更多你可能会觉得有用的dlr plumbing features