【问题标题】:Define a calculated property on an expando object在 expando 对象上定义计算属性
【发布时间】:2013-02-11 16:28:18
【问题描述】:

我正在使用 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 代理项,其值实际上是方法的结果。这似乎是不可能的(除非我错过了什么,否则也没有多大意义——基本上你会有一个设置为“委托”的值,然后作为委托返回值获取???)。我是正确的还是这个或我遗漏了什么?

【问题讨论】:

    标签: c# dynamic expandoobject


    【解决方案1】:

    您需要通过继承 DynamicObject 并覆盖来创建自己的 ExpandoObject

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

    实现TrySetMember 将值存储在binder.Name 下的私有Dictionary&lt;string,object&gt; 中,并使用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,您可能会觉得有用。

    【讨论】:

    • 是的,实际上我认为有一个类似的解决方案 - 但我想知道如果没有自定义代码这是否可行(并不是说我无法添加它 - 毕竟我的 expando 对象已经是自定义继承的类)通过使用表达式树等。无论如何,如果没有其他方式将发布,我会接受这是最合适的^_^
    • 好的,现在我接受这个。这是一种解决方法,但我想这也是让“计算属性”表现得像普通属性的唯一方法。由于我已经扩展了基础 expando 以支持其他行为(我使用了一个安全的 expando,它为未定义的属性返回 null),我想我可以这样做(实际上这是我的第一个想法,但我还是发布了这个问题以查看如果我遗漏了什么)。谢谢 jbtule,我也会看看你的库——总有东西要学。
    猜你喜欢
    • 1970-01-01
    • 2015-09-20
    • 2020-01-15
    • 2018-07-19
    • 2021-06-10
    • 2017-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多