7

我正在使用 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?";
        }));  

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

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

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

有没有办法做到这一点?我相信我可以通过使用表达式树来做到这一点,但我承认我有点迷路了。任何人都可以就如何实现这一目标提供一些指导吗?


编辑

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

似乎由于 TryGetMember 只是返回一个值,因此没有办法让它“执行”属性代码。为了实现这一点,您需要某种表达式/lambda/func/action 代理项,其值实际上是方法的结果。这似乎是不可能的(除非我错过了什么,否则也没有多大意义——基本上你会有一个设置为“委托”的值,然后作为委托返回值获取???)。我是正确的还是这个或者我错过了什么?

4

1 回答 1

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。然后给它你需要的功能,添加一个 check in 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 管道功能。

于 2013-02-11T17:05:06.410 回答