How to set a property of a C# 4 dynamic object when you have the name in another variable

I'm looking for a way to modify properties on a dynamic C# 4.0 object with the name of the property known only at runtime.

Is there a way to do something like (ExpandoObject is just used as an example, this could be any class that implements IDynamicMetaObjectProvider):

string key = "TestKey";
dynamic e = new ExpandoObject();
e[key] = "value";

Which would be equivalent to:

dynamic e = new ExpandoObject();
e.TestKey = "value";

Or is the only way forward reflection?


Not very easily, no. Reflection doesn't work, since it assumes a regular type model, which is not the full range of dynamic. If you are actually just talking to regular objects, then just use reflection here. Otherwise, I expect you may want to reverse-engineer the code that the compiler emits for a basic assignment, and tweak it to have a flexibly member-name. I'll be honest, though: this isn't an attractive option; a simple:

dynamic foo = ...
foo.Bar = "abc";

translates to:

if (<Main>o__SiteContainer0.<>p__Site1 == null)
{
    <Main>o__SiteContainer0.<>p__Site1 = CallSite<Func<CallSite, object, string, object>>.Create(Binder.SetMember(CSharpBinderFlags.None, "Bar", typeof(Program), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant | CSharpArgumentInfoFlags.UseCompileTimeType, null) }));
}
<Main>o__SiteContainer0.<>p__Site1.Target(<Main>o__SiteContainer0.<>p__Site1, foo, "abc");

If you want an approach that works for both dynamic and non-dynamic objects: FastMember is handy for this, and works at either the type or object level:

// could be static or DLR 
var wrapped = ObjectAccessor.Create(obj); 
string propName = // something known only at runtime 
Console.WriteLine(wrapped[propName]);

available on Nuget, and heavily optimised for both dynamic and non-dynamic scenarios.


To add to Jonas' answer, you don't have to create a new var p. Use this approach instead:

using System;
using System.Dynamic;

class Program
{
    static void Main(string[] args)
    {
        dynamic expando = new ExpandoObject();
        ((IDictionary<String, object>)expando)["A"] = "New val 1";
        ((IDictionary<String, object>)expando)["B"] = "New val 2";

        Console.WriteLine(expando.A);
        Console.WriteLine(expando.B);
    }
}