tags:

views:

180

answers:

1

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 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 it could be a custom implementation which is not reflection based (e.g. by extending DynamicObject and doing its own thing).

+4  A: 

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"));
    }
}
Jon Skeet
Very nice, thanks Jon! That brings a lot of concepts that I haven't dealt with, so I'll need to study it carefully.It feels strange that typeof(Test) is used in there, since it should be of no relevance. But I tried setting it to null and the code still works, so apparently it wasn't doing much.
David Ebbo
It's relevant in terms of what members are accessible - you'll be able to get at private members of Test using this code, but not private members of other types.
Jon Skeet