Daily Knowledge Drop
The ExpandoObject
class implements IEnumberable
and IDictionary
- this means its fields can be iterated over, and that it can be converted to, and operated on as a Dictionary.
ExpandoObject
First some information on the ExpandoObject
class - it enables one to add and deleted members of its instance at runtime.
dynamic infoObject = new ExpandoObject();
infoObject.Name = "Always Developing";
infoObject.Url = "www.alwaysdeveloping.net";
Console.WriteLine(infoObject.Name);
Console.WriteLine(infoObject.Url);
In the above example, the properties Name and Age are dynamically added at runtime. Any number of properties, of any type can dynamically be added.
The ExpandoObject
can also have methods (Action and Func) added dynamically, and then invoked:
dynamic infoObject = new ExpandoObject();
infoObject.Name = "Always Developing";
infoObject.Url = "www.alwaysdeveloping.net";
infoObject.Visitors = 0;
infoObject.IncreaseVisitorCount = (Action)(() => { infoObject.Visitors++; });
infoObject.GetVisitorCount = (Func<int>)(() => { return infoObject.Visitors; });
infoObject.IncreaseVisitorCount();
infoObject.IncreaseVisitorCount();
Console.WriteLine(infoObject.GetVisitorCount());
The IncreaseVisitorCount Action and GetVisitorCount Func are dynamically added, and then invoked.
The output of the above being 2
, as expected, as the IncreaseVisitorCount method is invoked twice.
IEnumerable conversion
As ExpandoObject
implement IEnumberable, specifically IEnumerable<KeyValuePair<string, object?>>
and can be iterated over, with a KeyValuePair<string, object?>
item returned for each iteration:
dynamic infoObject = new ExpandoObject();
infoObject.Name = "Always Developing";
infoObject.Url = "www.alwaysdeveloping.net";
infoObject.Visitors = 0;
infoObject.IncreaseVisitorCount = (Action)(() => { infoObject.Visitors++; });
infoObject.GetVisitorCount = (Func<int>)(() => { return infoObject.Visitors; });
// prop is of type KeyValuePair<string, object?>
foreach (var prop in infoObject)
{
Console.WriteLine($"Key: '{prop.Key}' with value '{prop.Value}'");
}
In the above, iterating over infoObject will return each property dynamically added to the ExpandoObject
instance, including methods:
Key: 'Name' with value 'Always Developing'
Key: 'Url' with value 'www.alwaysdeveloping.net'
Key: 'Visitors' with value '2'
Key: 'IncreaseVisitorCount' with value 'System.Action'
Key: 'GetVisitorCount' with value 'System.Func`1[System.Int32]'
Dictionary conversion
ExpandoObject
also implements IDictionary<string, object?>
, so can directly be assigned to this type:
dynamic infoObject = new ExpandoObject();
infoObject.Name = "Always Developing";
infoObject.Url = "www.alwaysdeveloping.net";
infoObject.Visitors = 0;
infoObject.IncreaseVisitorCount = (Action)(() => { infoObject.Visitors++; });
infoObject.GetVisitorCount = (Func<int>)(() => { return infoObject.Visitors; });
// cast ExpandoObject to IDictionary<string, object?>
IDictionary<string, object?> dictionary = infoObject;
foreach (var item in dictionary)
{
Console.WriteLine($"Key: '{item.Key}' with value '{item.Value}'");
}
The output of the above the same as the first example:
Key: 'Name' with value 'Always Developing'
Key: 'Url' with value 'www.alwaysdeveloping.net'
Key: 'Visitors' with value '2'
Key: 'IncreaseVisitorCount' with value 'System.Action'
Key: 'GetVisitorCount' with value 'System.Func`1[System.Int32]'
Casting to Dictionary
allows one to check if a property/key has been added to the ExpandoObject
:
IDictionary<string, object?> dictionary = infoObject;
foreach (var item in dictionary)
{
Console.WriteLine($"Key: '{item.Key}' with value '{item.Value}'");
}
// This would result in an exception
// var value = infoObject["Name"];
// On a dictionary, this is allowed
if (dictionary.ContainsKey("Name"))
{
Console.WriteLine(dictionary["Name"]);
}
Notes
This is a small, but useful piece of knowledge to be aware of if working with ExpandoObject
as the ability to easily convert to other types opens up new operations and possibilities on the instance.
References
C# Tip: Convert ExpandoObjects to IDictionary
Daily Drop 101: 22-06-2022
At the start of 2022 I set myself the goal of learning one new coding related piece of knowledge a day.
It could be anything - some.NET / C# functionality I wasn't aware of, a design practice, a cool new coding technique, or just something I find interesting. It could be something I knew at one point but had forgotten, or something completely new, which I may or may never actually use.
The Daily Drop is a record of these pieces of knowledge - writing about and summarizing them helps re-enforce the information for myself, as well as potentially helps others learn something new as well.