C# Tip: Convert ExpandoObjects to IDictionary

In C#, ExpandoObjects
are dynamically-populated objects without a predefined shape.
1 2 3 |
<span class="token class-name"><span class="token keyword">dynamic</span></span> myObj <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">ExpandoObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> myObj<span class="token punctuation">.</span>Name <span class="token operator">=</span><span class="token string">"Davide"</span><span class="token punctuation">;</span> myObj<span class="token punctuation">.</span>Age <span class="token operator">=</span> <span class="token number">30</span><span class="token punctuation">;</span> |
Name
and Age
are not part of the definition of ExpandoObject
: they are two fields I added without declaring their type.
This is a dynamic object, so I can add new fields as I want. Say that I need to add my City: I can simply use
1 |
myObj<span class="token punctuation">.</span>City <span class="token operator">=</span> <span class="token string">"Turin"</span><span class="token punctuation">;</span> |
without creating any field on the ExpandoObject
class.
Now: how can I retrieve all the values? Probably the best way is by converting the ExpandoObject
into a Dictionary
.
Create a new Dictionary
Using an IDictionary
makes it easy to access the keys of the object.
If you have an ExpandoObject
that will not change, you can use it to create a new IDictionary
:
1 2 3 |
<span class="token class-name"><span class="token keyword">dynamic</span></span> myObj <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">ExpandoObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> myObj<span class="token punctuation">.</span>Name <span class="token operator">=</span><span class="token string">"Davide"</span><span class="token punctuation">;</span> myObj<span class="token punctuation">.</span>Age <span class="token operator">=</span> <span class="token number">30</span><span class="token punctuation">;</span> <span class="token class-name">IDictionary<span class="token punctuation"><</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token punctuation">?</span><span class="token punctuation">></span></span> dict <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">Dictionary<span class="token punctuation"><</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token punctuation">?</span><span class="token punctuation">></span></span><span class="token punctuation">(</span>myObj<span class="token punctuation">)</span><span class="token punctuation">;</span> myObj<span class="token punctuation">.</span>City <span class="token operator">=</span><span class="token string">"Turin"</span><span class="token punctuation">;</span> |
Notice that we use the ExpandoObject
to create a new IDictionary
. This means that after the Dictionary creation if we add a new field to the ExpandoObject
, that new field will not be present in the Dictionary.
Cast to IDictionary
If you want to use an IDictionary to get the ExpandoObject
keys, and you need to stay in sync with the ExpandoObject
status, you just have to cast that object to an IDictionary
1 2 3 |
<span class="token class-name"><span class="token keyword">dynamic</span></span> myObj <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">ExpandoObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> myObj<span class="token punctuation">.</span>Name <span class="token operator">=</span><span class="token string">"Davide"</span><span class="token punctuation">;</span> myObj<span class="token punctuation">.</span>Age <span class="token operator">=</span> <span class="token number">30</span><span class="token punctuation">;</span> <span class="token class-name">IDictionary<span class="token punctuation"><</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token punctuation">?</span><span class="token punctuation">></span></span> dict <span class="token operator">=</span> myObj<span class="token punctuation">;</span> myObj<span class="token punctuation">.</span>City <span class="token operator">=</span><span class="token string">"Turin"</span><span class="token punctuation">;</span> |
This works because ExpandoObject
implements IDictionary
, so you can simply cast to IDictionary without instantiating a new object.
Here’s the class definition:
1 |
<span class="token keyword">public</span> <span class="token keyword">sealed</span> <span class="token keyword">class</span> <span class="token class-name">ExpandoObject</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">IDynamicMetaObjectProvider</span><span class="token punctuation">,</span> <span class="token class-name">IDictionary<span class="token punctuation"><</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token punctuation">?</span><span class="token punctuation">></span></span><span class="token punctuation">,</span> <span class="token class-name">ICollection<span class="token punctuation"><</span>KeyValuePair<span class="token punctuation"><</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token punctuation">?</span><span class="token punctuation">></span><span class="token punctuation">></span></span><span class="token punctuation">,</span> <span class="token class-name">IEnumerable<span class="token punctuation"><</span>KeyValuePair<span class="token punctuation"><</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token punctuation">?</span><span class="token punctuation">></span><span class="token punctuation">></span></span><span class="token punctuation">,</span> <span class="token class-name">IEnumerable</span><span class="token punctuation">,</span> <span class="token class-name">INotifyPropertyChanged</span></span> |
Wrapping up
Both approaches are correct. They both create the same Dictionary
, but they act differently when a new value is added to the ExpandoObject
.
Can you think of any pros and cons of each approach?
Happy coding!
🐧
Source: https://www.code4it.dev/csharptips/expandoobject-to-dictionary