Dynamically adding properties to an ExpandoObject
Asked Answered
W

4

296

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?

Wen answered 8/2, 2011 at 21:1 Comment(1)
possible duplicate of How to set a property of a C# 4 dynamic object when you have the name in another variableDisapprobation
G
615
dynamic x = new ExpandoObject();
x.NewProp = string.Empty;

Alternatively:

var x = new ExpandoObject() as IDictionary<string, Object>;
x.Add("NewProp", string.Empty);
Greenhorn answered 8/2, 2011 at 21:5 Comment(11)
I've never realized that Expando implements IDictionary<string, object>. 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 lotGenic
It is amazing, and I have demonstrate that they are actually becoming properties of the object with sample code in my post on #11888644, thanksHigher
getting Error 53 Cannot convert type 'System.Dynamic.ExpandoObject' to 'System.Collections.Generic.IDictionary<string,string>' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversionHeadset
It's IDictionary<string, object>, not IDictionary<string, string>.Greenhorn
It might not be a good idea to cast to dictionary and add properties. connect.microsoft.com/VisualStudio/feedback/details/783541/…Haman
@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.Greenhorn
May worth pointing out the first one doesn't work with var x. It only works with dynamic x.Hemminger
It's important to note that when you're casting as IDictionary that you don't use dynamic as the variable type.Final
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<string, object> myExpando = new ExpandoObject();Hopeh
Nullability required in my case: IDictionary<string, object?> dynamicObject = new ExpandoObject();Inhalator
@Headset you might also get this error if you are not 'using System;' - because compiler does not recognize the type 'Object' i.e. System.ObjectAquiline
H
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();
Hhour answered 15/10, 2015 at 19:37 Comment(2)
Your code is plain wrong, you skipped the most important part, which is the cast to a Dictionary.Simms
@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.Hhour
B
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");
Bellbottoms answered 23/1, 2017 at 15:28 Comment(2)
"var expandoDict = expando as IDictionary;" this line need to change to "var expandoDict = expando as IDictionary<String, object>;"Janijania
To make it even more awesome use those as extension methods.Beefwood
F
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);
    }
Fourier answered 22/10, 2022 at 23:1 Comment(1)
Might not be as elegant as IDictionary, but only working solution if you later use this variable as dynamic (eg dynamic.Properties())Ier

© 2022 - 2024 — McMap. All rights reserved.