如何直接调用DynamicObject.TryGetMember?
我正在实现一个通用函数来从任意提供的动态对象中提取值,但不知道如何调用 TryGetMember
因为它需要一个抽象的 GetMemberBinder
,因此我无法创建它。 示例...
public object GetValue(DynamicObject Source, string FieldName)
{
object Result = null;
GetMemberBinder Binder = x; // What object must be provided?
Binder.Name = FieldName;
if (Source.TryGetMember(Binder, out Result))
return Result;
throw new Exception("The field '" + FieldName + "' not exists");
}
是否有已存在的 GetMemberBinder 具体后代可供使用?或者创建我自己的实现的指南?
I'm implementing a general purpose function to extract a value from an arbitrary provided dynamic object, but don't know how to call TryGetMember
because it requires a GetMemberBinder
which is abstract, hence I cannot create it.
Sample...
public object GetValue(DynamicObject Source, string FieldName)
{
object Result = null;
GetMemberBinder Binder = x; // What object must be provided?
Binder.Name = FieldName;
if (Source.TryGetMember(Binder, out Result))
return Result;
throw new Exception("The field '" + FieldName + "' not exists");
}
Is there an already existent concrete descendant of GetMemberBinder ready for use? or a guideline to create my own implementation?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我不确定框架中是否有任何方法实际上返回
GetMemberBinder
,但这并不重要 - 这不是按名称调用动态成员的正确方法。您实际上需要做的是创建一个调用站点。该方法如下所示:
请注意,
Binder.GetMember
创建一个CallSiteBinder
,而不是创建一个GetMemberBinder
。只是为了100%清楚。如果对TryGetMember
的内部调用失败,此方法将抛出RuntimeBinderException
,因此您无需检查结果。如果您不希望调用者看到 RuntimeBinderException,请将其包装在您自己的 try/catch 中。动态调度很复杂,至少相对于静态类型的反射而言是这样。由于 CLR 实际上并不是动态类型的,因此 C# 必须实际实例化一个编译器来弄清楚如何执行成员/方法。这就是创建一个调用站点。据我所知,您必须这样做,这就是为什么每个
Binder
方法都会返回一个CallSiteBinder
并且您无法实例化任何直接使用粘合剂。请注意,DLR 执行某种调用站点缓存,但我不确定自动缓存是否涵盖这种情况。您很有可能希望保存调用站点以供将来调用,以避免不断重新编译的开销。
PS如果您正在使用(或可以使用)
ExpandoObject
而不是DynamicObject
,那么请记住它实现了IDictionary
,所以你不需要做任何这些。只需将其转换为字典类型并检查该属性是否存在即可。如果我要做的事情比简单地在运行时添加成员复杂得多,即根据运行时绑定器更改实际行为,我只会使用DynamicObject
而不是ExpandoObject
。I'm not sure if there's any method in the framework that actually returns a
GetMemberBinder
, but it doesn't matter - that isn't the correct way to invoke a dynamic member by name.What you actually need to do is create a call site. The method looks like this:
Note that
Binder.GetMember
creates aCallSiteBinder
, not aGetMemberBinder
. Just to be 100% clear. This method will throw aRuntimeBinderException
if the internal call toTryGetMember
fails, so you do not need to check the result. If you don't want callers to see theRuntimeBinderException
then wrap it in your own try/catch.Dynamic dispatch is complex, at least relative to reflection on static types. Since the CLR is not actually dynamically typed, C# has to actually instantiate a compiler to figure out how to execute the member/method. That's creating a call site. As far as I know, you have to do this, which is why every
Binder
method returns aCallSiteBinder
and you can't instantiate any of the binders directly.Note that the DLR does some sort of call site caching, but I'm not sure if the automatic caching covers this scenario. There's a good chance you'll want to save your call site for future calls to avoid the overhead of constant recompilation.
P.S. If you are using (or can use)
ExpandoObject
instead ofDynamicObject
then keep in mind that it implementsIDictionary<string, object>
, so you don't need to do any of this. Just cast it to the dictionary type and check if the property exists. I would only ever useDynamicObject
overExpandoObject
if I were doing something a lot more complicated than simply adding members at runtime, i.e. changing the actual behaviour based on the runtime binder.您不直接调用 TryGetMember,您需要的是直接使用动态 api,通过使用 csharp 成员绑定器和调用站点来获得相同的效果。
开源框架 Dynamitey (通过 nuget)使这变得更加容易,因为它有一个静态方法可以执行此操作。它适用于任何 IDynamicMetaObjectProvider,而不仅仅是 DynamicObject(它适用于常规类型也比反射更快)。
You don't call TryGetMember directly, what you need is to use the dynamic api's directly to get the same effect by using a csharp member binder and a call site.
This is made even easier by open source framework Dynamitey (via nuget) as it has a static method that does this. It works for any IDynamicMetaObjectProvider not just DynamicObject and (it works for regular types faster than reflection too).
虽然 Aaronaught 的回答解释了手动执行某些操作的“正确”方法,我相信 Dynamity 已经为您做到了这一点,但它实际上并没有回答发布者的问题。
问题问的是如何直接调用 TryGetMember( ),其他人不应该对原始发布者这样做的兴趣是否适当做出判断。
要真正回答这个问题,只有一个抽象成员,不包括构造函数。在我的应用程序中,以下具体类就足够了,我相信最有效的解决方案:
Microsoft 有关 FallbackGetMember( ) 方法的文档非常有限,可以在 此处。在我看来,如果您知道所讨论的动态对象将成功提供结果,或者您可以将您的尝试包装在 try/catch 块中以处理它不提供结果的情况,那么 FallbackGetMember( ) 不需要予以实施。但是,如果您需要完整的动态调度支持,那么 Aaronaught 的答案和 Dynamity 可能是更明智的解决方案 - 但这根本不是问题所问的。
就我而言,我有一个动态对象,当调用 TryGetMember() 时,它永远不会失败,因此真正的动态分派的开销似乎非常昂贵。
While Aaronaught's answer explains what might be the "right" way to do something manually that I believe Dynamity already does for you, it does not actually answer the poster's question.
The question asks how to call TryGetMember( ) directly, and others should not pass judgement on the propriety of the original poster's interest in doing so.
To actually answer the question, there is only one abstract member, not counting the constructor. In my application, the following concrete class is sufficient, and I believe the most efficient solution:
Microsoft has very limited documentation on the FallbackGetMember( ) method that can be found here. It appears to me that if you either know that the dynamic object in question will successfully provide a result, or you can wrap your attempt in a try/catch block in order to handle cases where it does not, then the FallbackGetMember( ) need not be implemented. If, however, you require full dynamic dispatch support, then Aaronaught's answer and Dynamity might be the more advisable solution--that simply is not what the question asks though.
In my case, I have a dynamic object that never fails to produce a successful result when TryGetMember( ) is called, so the overhead of true dynamic dispatch seems unreasonably expensive.