我正在使用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代理,该值实际上是方法的结果。这似乎是不可能的(除非我错过了某些东西,否则也没有多大意义 - 基本上你会有一个设置为'委托'的值,然后作为委托返回值得到???)。我是正确的还是我还是错过了什么?
答案 0 :(得分:2)
您需要通过继承DynamicObject
并覆盖
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。