C#
ExpandoObject
DynamicObject
dynamic programming
.NET

Differences between ExpandoObject, DynamicObject and dynamic

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

dynamic, ExpandoObject, and DynamicObject are related in C#, but they are not interchangeable. dynamic is a language feature that postpones member binding until runtime, ExpandoObject is a ready-made dynamic object whose members can be added at runtime, and DynamicObject is a base class for implementing your own custom dynamic behavior.

The easiest way to keep them straight is to remember that only two of them are object models. dynamic is not a container type. It changes how the compiler treats an expression.

dynamic Is A Binding Mode

The dynamic keyword tells the compiler not to perform its normal static member checks for that expression:

csharp
1using System;
2
3dynamic value = "hello";
4Console.WriteLine(value.Length);

This compiles because the actual member lookup is deferred to runtime. If the object does not support the requested member, the program fails at runtime with a binder error instead of at compile time.

So dynamic is about binding semantics, not about what kind of object you stored.

ExpandoObject Is A Dynamic Bag Of Members

ExpandoObject is a concrete type in .NET that lets you add and remove members dynamically:

csharp
1using System;
2using System.Dynamic;
3
4dynamic person = new ExpandoObject();
5person.Name = "Alice";
6person.City = "Toronto";
7
8Console.WriteLine(person.Name);
9Console.WriteLine(person.City);

This is useful when you need a lightweight object with flexible shape, such as ad hoc view-model data or simple JSON-like objects.

Under the hood, ExpandoObject also behaves like a dictionary of member names and values, which makes it convenient when the set of properties is not known in advance.

DynamicObject Is For Custom Rules

DynamicObject is different. It is a base class you inherit from when you want to define how dynamic access should behave:

csharp
1using System;
2using System.Collections.Generic;
3using System.Dynamic;
4
5class MyDynamic : DynamicObject
6{
7    private readonly Dictionary<string, object> _values = new();
8
9    public override bool TrySetMember(SetMemberBinder binder, object value)
10    {
11        _values[binder.Name] = value;
12        return true;
13    }
14
15    public override bool TryGetMember(GetMemberBinder binder, out object result)
16    {
17        return _values.TryGetValue(binder.Name, out result);
18    }
19}
20
21dynamic obj = new MyDynamic();
22obj.Title = "Report";
23Console.WriteLine(obj.Title);

This approach is appropriate when you want validation, computed members, logging, proxying, or a backing store that is more complex than a simple property bag.

How They Fit Together

These three ideas often appear together:

  • 'dynamic can reference an ExpandoObject'
  • 'dynamic can reference an instance of a DynamicObject subclass'
  • 'dynamic can also reference an ordinary object'

That is why comparing them as if they were sibling types can be misleading. A more accurate description is:

  • 'dynamic changes member resolution behavior'
  • 'ExpandoObject gives you a built-in dynamic data object'
  • 'DynamicObject lets you define your own dynamic semantics'

When To Use Which One

Use dynamic when you need runtime binding for an object whose shape is not known statically. Use ExpandoObject when you want a flexible object without writing custom behavior. Use DynamicObject when you want full control over how dynamic member access behaves.

If a normal strongly typed class will do the job, it is usually the better choice. Strong typing improves refactoring, tooling, and compiler feedback.

Common Pitfalls

The biggest mistake is thinking dynamic is a replacement for ExpandoObject or DynamicObject. It is not. It is a keyword that affects how C# resolves members.

Another pitfall is overusing dynamic code where a normal class would be clearer and safer. You lose compile-time checking, which increases the chance of runtime errors.

A third issue is choosing DynamicObject when ExpandoObject would already be sufficient. If you just need a flexible property bag, the built-in type is simpler.

Summary

  • 'dynamic is a language feature that defers binding to runtime.'
  • 'ExpandoObject is a built-in dynamically extensible object.'
  • 'DynamicObject is a base class for implementing custom dynamic behavior.'
  • 'dynamic can be used with either of those object models or with ordinary objects.'
  • Prefer strong typing unless runtime flexibility is genuinely required.

Course illustration
Course illustration

All Rights Reserved.