How to call DynamicObject.TryGetMember directly?

I am implementing a general purpose function to extract a value from an arbitrary provided dynamic object, but I don’t know how to call TryGetMember because it requires GetMemberBinder , which is abstract, so I cannot create it. Example...

 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 existing concrete descendant of GetMemberBinder ready to use? or a guide to creating my own implementation?

+23
dynamic
Mar. 14 '11 at 23:52
source share
2 answers

I'm not sure if there is any method in the structure that GetMemberBinder actually returns, but it does not matter - this is not the right way to call a dynamic member by name.

What you really need to do is create a call site. The method is as follows:

 static object GetDynamicMember(object obj, string memberName) { var binder = Binder.GetMember(CSharpBinderFlags.None, memberName, obj.GetType(), new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }); var callsite = CallSite<Func<CallSite, object, object>>.Create(binder); return callsite.Target(callsite, obj); } 

Note that Binder.GetMember creates a CallSiteBinder , not a GetMemberBinder . Just to be 100% clear. This method throws a RuntimeBinderException if the internal call to TryGetMember fails, so you do not need to check the result. If you do not want callers to see a RuntimeBinderException , then wrap it in your own try / catch.

Dynamic dispatch is complicated, at least in terms of reflection on static types. Since the CLR is not actually dynamically typed, C # must actually instantiate the compiler to figure out how to execute the element / method. This is the creation of a call site. As far as I know, you should do this, so each Binder method returns a CallSiteBinder , and you cannot directly create any binders.

Note that DLR does some kind of caching of the call site, but I'm not sure that automatic caching covers this scenario. There is a good chance that you will want to keep your site for future calls in order to avoid the overhead of constantly recompiling.

PS If you use (or can use) ExpandoObject instead of DynamicObject , then keep in mind that it implements IDictionary<string, object> , so you do not need to do anything. Just enter it into the dictionary type and check if the property exists. I would only use DynamicObject over ExpandoObject , if I would do something much more complicated than just adding elements at runtime, i.e. Changing the actual behavior based on middleware runtime.

+47
Aug 18 2018-11-18T00:
source share

You do not call TryGetMember directly, you need to use the dynamic api directly to get the same effect using the csharp connecting element and the call site.

This is made even easier with the Dynamitey open source framework (via nuget), as it has a static method that does this. It works for any IDynamicMetaObjectProvider not only DynamicObject and (it works for ordinary types faster than reflection too).

 return Dynamic.InvokeGet(Source, FieldName); 
+11
Mar 15 '11 at 16:10
source share



All Articles