Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Invoke a member of a dynamic object with a name defined at runtime in a String

I want to access a property on an object while leveraging the DLR binding mechanism.

  • I cannot use the native binding mechanism (dynamic keyword in C#) because I do not know the property name at compile-time;
  • I cannot use reflection because it only retrieves static type information;
  • casting to an IDictionary<string, object>, to my knowledge, only solves the case of dynamic classes that choose to implement that interface (such as ExpandoObject).

Here is the demonstration code:

    static void Main(string[] args)
    {
        dynamic obj = new System.Dynamic.ExpandoObject();
        obj.Prop = "Value";
        // C# dynamic binding.
        Console.Out.WriteLine(obj.Prop);
        // IDictionary<string, object>
        Console.Out.WriteLine((obj as IDictionary<string, object>)["Prop"]);
        // Attempt to use reflection.
        PropertyInfo prop = obj.GetType().GetProperty("Prop");
        Console.Out.WriteLine(prop.GetValue(obj, new object[] { }));
        Console.In.ReadLine();
    }
like image 372
Jean Hominal Avatar asked Jun 27 '11 10:06

Jean Hominal


People also ask

How to handle dynamic objects in c#?

You can create custom dynamic objects by using the classes in the System. Dynamic namespace. For example, you can create an ExpandoObject and specify the members of that object at run time. You can also create your own type that inherits the DynamicObject class.

What is dynamic in. net core?

The dynamic language runtime (DLR) is an API that was introduced in . NET Framework 4. It provides the infrastructure that supports the dynamic type in C#, and also the implementation of dynamic programming languages such as IronPython and IronRuby.

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

I was finally able to do it by using the C# runtime binder. (I believe it should be possible to do that with a simpler binder implementation, but I was unable to write a working one - probably writing a "simple" implementation is already quite tough).

using Microsoft.CSharp.RuntimeBinder;

    private class TestClass
    {
        public String Prop { get; set; }
    }

    private static Func<object, object> BuildDynamicGetter(Type targetType, String propertyName)
    {
        var rootParam = Expression.Parameter(typeof(object));
        var propBinder = Microsoft.CSharp.RuntimeBinder.Binder.GetMember(CSharpBinderFlags.None, propertyName, targetType, new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) });
        DynamicExpression propGetExpression = Expression.Dynamic(propBinder, typeof(object), 
            Expression.Convert(rootParam, targetType));
        Expression<Func<object, object>> getPropExpression = Expression.Lambda<Func<object, object>>(propGetExpression, rootParam);
        return getPropExpression.Compile();
    }

    static void Main(string[] args)
    {
        dynamic root = new TestClass { Prop = "StatValue" };

        Console.Out.WriteLine(root.Prop);
        var dynGetter = BuildDynamicGetter(root.GetType(), "Prop");
        Console.Out.WriteLine(dynGetter(root));

        root = new System.Dynamic.ExpandoObject();
        root.Prop = "ExpandoValue";

        Console.WriteLine(BuildDynamicGetter(root.GetType(), "Prop").Invoke(root));
        Console.Out.WriteLine(root.Prop);
        Console.In.ReadLine();
    }

Output:

StatValue
StatValue
ExpandoValue
ExpandoValue
like image 189
Jean Hominal Avatar answered Oct 03 '22 11:10

Jean Hominal


The opensource framework dynamitey will do this (available via nuget). It uses that same api calls as the c# compiler.

Console.Out.WriteLine(Dynamic.InvokeGet(obj,"Prop"));
like image 24
jbtule Avatar answered Oct 03 '22 11:10

jbtule