294

I would like to dynamically add properties to a ExpandoObject at runtime. So for example to add a string property call NewProp I would like to write something like

var x = new ExpandoObject();
x.AddProperty("NewProp", System.String);

Is this easily possible?

dkackman
  • 15,179
  • 13
  • 69
  • 123
Craig
  • 36,306
  • 34
  • 114
  • 197
  • possible duplicate of [How to set a property of a C# 4 dynamic object when you have the name in another variable](http://stackoverflow.com/questions/3033410/how-to-set-a-property-of-a-c-sharp-4-dynamic-object-when-you-have-the-name-in-an) – nawfal Jul 19 '14 at 15:55

5 Answers5

609
dynamic x = new ExpandoObject();
x.NewProp = string.Empty;

Alternatively:

var x = new ExpandoObject() as IDictionary<string, Object>;
x.Add("NewProp", string.Empty);
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • 42
    I've never realized that Expando *implements* IDictionary. I've always thought that cast would copy it to a dictionary. However, your post made me understand that if you change the Dictionary, you also change the underlying ExpandoObject! Thanks a lot – Dynalon Jan 27 '12 at 18:48
  • It is amazing, and I have demonstrate that they are actually becoming properties of the object with sample code in my post on http://stackoverflow.com/questions/11888144/name-variable-using-string-net/11893463#11893463, thanks – yoel halb Aug 10 '12 at 02:42
  • 3
    getting `Error 53 Cannot convert type 'System.Dynamic.ExpandoObject' to 'System.Collections.Generic.IDictionary' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion` – TheVillageIdiot Oct 30 '12 at 09:23
  • 27
    It's `IDictionary`, not `IDictionary`. – Stephen Cleary Oct 30 '12 at 13:29
  • It might not be a good idea to cast to dictionary and add properties. https://connect.microsoft.com/VisualStudio/feedback/details/783541/expandoobjects-leak-memory-when-used-as-an-idictionary-string-object-to-add-new-properties – Marko Jan 16 '15 at 10:52
  • @Marko: That "leak" is only if you add many different property names, and would have the same exact behavior if you added the same property names via `dynamic`. – Stephen Cleary Jan 16 '15 at 14:27
  • 1
    May worth pointing out the first one doesn't work with `var x`. It only works with `dynamic x`. – Adam Szabo Sep 14 '15 at 10:44
  • 12
    It's important to note that when you're casting as `IDictionary` that you don't use `dynamic` as the variable type. – user3791372 May 14 '17 at 17:42
  • 2
    If you implement as an IDictionary, then you don't have to cast it to use the methods from either the parent or derived class: `IDictionary myExpando = new ExpandoObject();` – Abel Wenning Mar 11 '21 at 00:14
  • Nullability required in my case: `IDictionary dynamicObject = new ExpandoObject();` – dystopiandev Mar 17 '23 at 12:10
33

As explained here by Filip - http://www.filipekberg.se/2011/10/02/adding-properties-and-methods-to-an-expandoobject-dynamicly/

You can add a method too at runtime.

var x = new ExpandoObject() as IDictionary<string, Object>;
x.Add("Shout", new Action(() => { Console.WriteLine("Hellooo!!!"); }));
x.Shout();
Chris Marisic
  • 32,487
  • 24
  • 164
  • 258
Himanshu Patel
  • 754
  • 8
  • 13
  • 2
    Your code is plain wrong, you skipped the most important part, which is the cast to a Dictionary. – tocqueville Nov 18 '20 at 15:17
  • @tocqueville, this answer is an enhancement to the current question and does not directly answer the question. The answer is an additional possibility. I hope you understand. – Himanshu Patel Dec 07 '22 at 11:06
22

Here is a sample helper class which converts an Object and returns an Expando with all public properties of the given object.

public static class dynamicHelper
    {
        public static ExpandoObject convertToExpando(object obj)
        {
            //Get Properties Using Reflections
            BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
            PropertyInfo[] properties = obj.GetType().GetProperties(flags);

            //Add Them to a new Expando
            ExpandoObject expando = new ExpandoObject();
            foreach (PropertyInfo property in properties)
            {
                AddProperty(expando, property.Name, property.GetValue(obj));
            }

            return expando;
        }

        public static void AddProperty(ExpandoObject expando, string propertyName, object propertyValue)
        {
            //Take use of the IDictionary implementation
            var expandoDict = expando as IDictionary<String, object>;
            if (expandoDict.ContainsKey(propertyName))
                expandoDict[propertyName] = propertyValue;
            else
                expandoDict.Add(propertyName, propertyValue);
        }
    }

Usage:

//Create Dynamic Object
dynamic expandoObj= dynamicHelper.convertToExpando(myObject);
    
//Add Custom Properties
dynamicHelper.AddProperty(expandoObj, "dynamicKey", "Some Value");
TECNO
  • 162
  • 2
  • 3
  • 15
Johannes
  • 541
  • 5
  • 6
2

This is the best solution I've found. But be careful with that. Use exception handling because it might not work on all of the cases

public static dynamic ToDynamic(this object obj)
{
    return JsonConvert.DeserializeObject<dynamic>(JsonConvert.SerializeObject(obj));
}

//another nice extension method you might want to use

    public static T JsonClone<T>(this T source)
    {
        if (!typeof(T).IsSerializable)
        {
            throw new ArgumentException("The type must be serializable.", nameof(source));
        }

        var serialized = JsonConvert.SerializeObject(source);
        return JsonConvert.DeserializeObject<T>(serialized);
    }
adi ben
  • 491
  • 5
  • 15
  • Might not be as elegant as IDictionary, but only working solution if you later use this variable as dynamic (eg dynamic.Properties()) – Laky Dec 07 '22 at 11:33
0

This is the best solution I've found. But be careful with that. Use exception handling because it might not work on all of the cases

    public static dynamic ToDynamic(this object obj)
    {
        return JsonConvert.DeserializeObject<dynamic>(JsonConvert.SerializeObject(obj));
    }
adi ben
  • 491
  • 5
  • 15