Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting a value from a dynamic object dynamically

Tags:

c#

dynamic

c#-4.0

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

like image 689
David Ebbo Avatar asked Dec 18 '09 07:12

David Ebbo


People also ask

How do you dynamically access object property in typescript?

To dynamically access an object's property: Use keyof typeof obj as the type of the dynamic key, e.g. type ObjectKey = keyof typeof obj; . Use bracket notation to access the object's property, e.g. obj[myVar] .

What is dynamic object in C#?

Dynamic objects expose members such as properties and methods at run time, instead of at compile time. This enables you to create objects to work with structures that do not match a static type or format.

What is an ExpandoObject?

The ExpandoObject class enables you to add and delete members of its instances at run time and also to set and get values of these members. This class supports dynamic binding, which enables you to use standard syntax like sampleObject. sampleMember instead of more complex syntax like sampleObject.


2 Answers

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"));
    }
}
like image 158
Jon Skeet Avatar answered Sep 20 '22 03:09

Jon Skeet


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);
}
like image 39
jbtule Avatar answered Sep 23 '22 03:09

jbtule