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

45,031

Solution 1

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.

Solution 2

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);
    }
}

Solution 3

My open source framework Dynamitey has methods for invoking based on string names using the DLR. It does the work of caching binding sites and streamlines it down to one method call. it also runs faster than reflection on non-dynamic objects too.

Dynamic.InvokeSet(e, "TestKey", "value");

Solution 4

fast-member may fit the bill - it looks like it generates the IL on the fly, but caches it so it's really fast after the first use.

Share:
45,031

Related videos on Youtube

Kieran Benton
Author by

Kieran Benton

Updated on February 18, 2022

Comments

  • Kieran Benton
    Kieran Benton about 2 years

    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?

    • James Black
      James Black almost 14 years
      Reflection is probably your own solution, unless you put your properties into a hashmap so they can be determined at runtime.
    • Kieran Benton
      Kieran Benton over 2 years
      I don't see why this should be closed as a duplicate - this is a specific question with a specific answer that is not addressed by the other question. There is unique information in here as to how to solve a problem - in fact the other question is much more 'discussion based' so I would argue it should be closed!
    • Kieran Benton
      Kieran Benton over 2 years
      I don't see why this should be closed as a duplicate - this is a specific question with a specific answer that is not addressed by the other question. There is unique information in here as to how to solve a problem - in fact the other question is much more 'discussion based' so I would argue it should be closed!
  • Kieran Benton
    Kieran Benton almost 14 years
    Thanks Marc - I thought I'd been missing something obvious but obviously not! :) Have you got any links to a good example of how to do code emission so I can give this a go? If I can get it going this looks like something work sharing!
  • Marc Gravell
    Marc Gravell almost 14 years
    @Kieran - it depends what you need. It didn't sound like you needed emission (the code I posted was just a sample of how ugly it is).
  • Andrew Hanlon
    Andrew Hanlon over 12 years
    Downvoted because this did not explain that an expandoObject uses a dictionary as its backing store and can be used exactly as the OP originally suggested. There is no need for reflection OR emit on an expandoObject. That said @MarcGravell is correct that for non-expando dynamic objects (as well as regular objects assigned to a dynamic var) there isn't a clean solution.
  • Marc Gravell
    Marc Gravell over 12 years
    @ach actually, I do now have a clean solution for this: FastMember. Will edit it in...
  • Marc Gravell
    Marc Gravell over 12 years
    @ach re your downvote: please read the question: "ExpandoObject is just used as an example, this could be any class that implements IDynamicMetaObjectProvider" - it would be entirely incorrect for me to focus on ExpandoObject as a dictionary.
  • Andrew Hanlon
    Andrew Hanlon over 12 years
    @MarcGravell Sorry, I will reverse my downvote, but maybe you should include mention of the expandoObject possibility. I really like the update about FastMember, awesome work.
  • Piotr Kula
    Piotr Kula almost 8 years
    FastMember does not support nested classes :( So I cannot use something like Person.Location.LocationID for example. This does work, Person.Location returns the class but what I should do. Create a loop where I wrap that class again and split against dots?
  • Craig Brunetti
    Craig Brunetti about 6 years
    FastMember would be useful to me if it worked with DynamicObject derivatives. It could be the glue between dynamically-sourced property data and concrete properties. @MarcGravell
  • Syed Rafay
    Syed Rafay almost 2 years
    @MarcGravell thank you so much, I am using Fast Member now. One question, other than Fast Member, is there any official Microsoft package out there doing the same thing?
  • Marc Gravell
    Marc Gravell almost 2 years
    @SyedRafay not AFAIK (and FastMember doesn't qualify either - it is neither official nor Microsoft-ish)
  • Syed Rafay
    Syed Rafay almost 2 years
    @MarcGravell okay, yeah i know its not an official package, but hey it does a pretty well job. So we are fine using it untill any official package is released which does the required job.