Yes, title sounds a bit confusing, so I'll explain what I mean: suppose you have a C# 4.0 'dynamic' object, and the name of a property. How would you 开发者_JS百科retrieve that property from the dynamic object?
In other words, how would you implement:
public static object GetDynamicValue(dynamic o, string name) { ... }
Another way to put it is that I'm trying to treat a dynamic object as an IDictionary.
Note that reflection is likely not an option here, since the dynamic object could be a custom implementation which is not reflection based (e.g. by extending DynamicObject and doing its own thing).
You would have to build a call site, create a binder etc.
The easiest way to see what happens is to compile this:
public static object GetDynamicValue(dynamic o, string name)
{
return o.Foo;
}
Then decompile it with Reflector and work out what it's doing. It'll be pretty complicated, mind you - and you'll need to change it from being a single, static, cached call site to creating a new one on each invocation.
Here's an example which does work... but whether it's entirely correct or not is a different matter :) (I got this going by doing exactly what I suggested above.)
using Microsoft.CSharp.RuntimeBinder;
using System;
using System.Dynamic;
using System.Runtime.CompilerServices;
class Test
{
public static object GetDynamicValue(dynamic o, string name)
{
CallSite<Func<CallSite, object, object>> site
= CallSite<Func<CallSite, object, object>>.Create
(Binder.GetMember(CSharpBinderFlags.None, name,
typeof(Test), new CSharpArgumentInfo[]
{ CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }));
return site.Target(site, o);
}
static void Main()
{
Console.WriteLine(GetDynamicValue("hello", "Length"));
}
}
The Open source framework ImpromptuInterface (available in nuget) does this, and does the extra work involved because caching the call site is important for performance.
See InvokeGet
public static object GetDynamicValue(dynamic o, string name) {
return Impromptu.InvokeGet(o,name);
}
精彩评论