Using ExpandoObject as a Dynamic Property Bag in C
The ExpandoObject class in C# provides an easy way to
add, modify, and delete object properties dynamically at runtime. This
article explains what ExpandoObject is, demonstrates how to
use it with the dynamic keyword, and shows how casting it
to an IDictionary<string, object?> enables you to
treat it as a flexible, dynamic property bag.
What Is ExpandoObject?
Defined in the System.Dynamic namespace,
ExpandoObject represents an object whose members can be
dynamically added and removed at runtime. It implements both dynamic
dispatching via the Dynamic Language Runtime (DLR) and standard
collection interfaces such as
IDictionary<string, object?> and
INotifyPropertyChanged.
Because it implements
IDictionary<string, object?>, an instance of
ExpandoObject acts as a dynamic property bag: you can
interact with it using conventional object member syntax, or you can
manipulate its internal state as key-value pairs.
Basic Usage with the dynamic Keyword
To use ExpandoObject with member-access syntax, declare
your variable with the dynamic keyword. You can immediately
assign values to properties that were never explicitly defined on a
class.
using System;
using System.Dynamic;
dynamic person = new ExpandoObject();
// Adding properties on the fly
person.FirstName = "Jane";
person.LastName = "Doe";
person.Age = 30;
// Adding dynamic behavior (methods/delegates)
person.GetFullName = (Func<string>)(() => $"{person.FirstName} {person.LastName}");
Console.WriteLine(person.GetFullName()); // Outputs: Jane Doe
Console.WriteLine(person.Age); // Outputs: 30Treating ExpandoObject as a Property Bag
The true power of ExpandoObject as a property bag
appears when you cast it to
IDictionary<string, object?>. This allows you to
inspect properties, read keys programmatically, remove properties, or
add data when property names are only known at runtime.
Adding and Accessing Properties Dynamically
You can set values using string keys and subsequently access them via dynamic syntax, or vice versa.
using System;
using System.Collections.Generic;
using System.Dynamic;
dynamic bag = new ExpandoObject();
var propertyBag = (IDictionary<string, object?>)bag;
// Add values using dictionary syntax
propertyBag["Department"] = "Engineering";
propertyBag["Salary"] = 95000;
// Access using dynamic member syntax
Console.WriteLine(bag.Department); // Outputs: Engineering
// Access using dictionary syntax
Console.WriteLine(propertyBag["Salary"]); // Outputs: 95000Enumerating Properties
Because it implements
IEnumerable<KeyValuePair<string, object?>>, you
can iterate over all currently defined members:
foreach (var kvp in (IDictionary<string, object?>)bag)
{
Console.WriteLine($"{kvp.Key}: {kvp.Value}");
}Checking for Property Existence and Deleting Properties
Unlike standard static types, an ExpandoObject allows
you to remove properties or verify their presence safely without
throwing a RuntimeBinderException.
var propertyBag = (IDictionary<string, object?>)bag;
// Check if a property exists
if (propertyBag.ContainsKey("Department"))
{
// Remove the property
propertyBag.Remove("Department");
}
// Attempting to access bag.Department now throws a RuntimeBinderExceptionCommon Use Cases
- Dynamic Data Mapping: Consuming arbitrary JSON or CSV structures where schemas vary across records.
- View Models and View Bags: Passing loosely-structured data across application layers without creating single-use DTO classes.
- Database Query Results: Mapping dynamic columns returned from flexible or schema-less SQL queries.