I came across a neat C# feature the other day - the ExpandoObject class. It’s been available since .Net 4, but I’d never seen it used in any of the codebases where I’ve worked. It combines with the ‘dynamic’ keyword (which I have come across, but only infrequently), and the Microsoft docs have this to say about the purpose:

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. ExpandoObject class - Microsoft

enter image description here

Given that C# is statically typed, I can see why this is infrequently used. This stackoverflow thread points out that a dictionary object can be used for many of the scenarios where one might want to add values for properties without creating a defined class structure up front:

My use case for this was that I have a number of interfaces that define how to translate properties of implementing classes into common formats. One of those formats uses JSON, but the property names within the JSON are defined by the value of a property on the implementing class. This means that to keep it generic, I needed a way to specify not just values but also properties in the JSON being created.

Of course there are other ways to do this. I could have created a statically typed class for mapping for each implementing class, but that seemed to add a lot of boilerplate that I didn’t want.

What are the true benefits of ExpandoObject? - stackoverflow

As the above link details, there are a couple of other benefits in addition to making it easier to manage multiple-level property hierarchies, which is a big obvious advantage over a dictionary structure. ExpandoObject itself implements INotifyPropertyChanged, so you can easily observe the object if needed. You can also include methods as members of an ExpandoObject.

Here is an example of using class property values to define the json property names in the context of translating a joke to pig latin:

    public class Joke : IPigLatin
    {
        public string Question { get; set; }

        public string Punchline { get; set; }

        public string TranslateToPigLatin()
        {
            return $"{PigLatin(Question)} {PigLatin(Punchline)}";
        }

        public string GetPigLatinJson()
        {
            PropertyInfo[] properties = this.GetType().GetProperties();
            dynamic expando = new ExpandoObject();
            foreach (PropertyInfo property in properties)
            {
                expando[(string)property.GetValue(this)] = PigLatin((string)property.GetValue(this));
            }
            return JsonSerializer.Serialize(expando);
        }

        private string PigLatin(string text)
        {
            //stolen from here https://stackoverflow.com/questions/34159453/english-to-piglatin-conversion-of-a-sentence
            const string vowels = "AEIOUaeio";
            List<string> pigWords = new List<string>();

            foreach (string word in text.Split(' '))
            {
                string firstLetter = word.Substring(0, 1);
                string restOfWord = word.Substring(1, word.Length - 1);
                int currentLetter = vowels.IndexOf(firstLetter);

                if (currentLetter == -1)
                {
                    pigWords.Add(restOfWord + firstLetter + "ay");
                }
                else
                {
                    pigWords.Add(word + "way");
                }
            }
            return string.Join(" ", pigWords);
        }
    }

    public interface IPigLatin
    {
        public string TranslateToPigLatin();

        public string GetPigLatinJson();
    }

Should you ever do this? Probably not usually, I mostly prefer well-defined models. But it might come in handy when interacting with a particularly dynamic external model (which is what I was encountering that led me to this class!)