With this tip, I will demonstrate creating a JavaScript-like dynamic object in C# with arbitrary gettable and settable fields using .NET's DLR technology. This allows for readable and writable/creatable fields on arbitrary objects without having to create a strongly typed object. It is especially useful in ASP.NET pages and T4 templates to enhance readability and flexibility.
Use ExpandoObject instead: I thought it had been deprecated in .NET 1.x - I was mistaken
Introduction
JavaScript allows for the creation of objects simply by assigning values to arbitrary fields, creating them on the fly. There is no direct equivalent in C#. However, with the .NET DLR, we can create one. This can allow for more readable field access in cases where you would otherwise use a dictionary.
Conceptualizing this Mess
With Dictionary
classes, you can get or set value by key, but if you're using them in ASP.NET pages, it can be somewhat clunky:
<%= obj["foo"] %>
What we really want is:
<%= obj.foo %>
Typically, C# will require you to use a strongly typed object instead of a dictionary for this, but that comes with two significant downsides: The first is it means extra coding. The second is you can't add arbitrary fields.
We're going to create a simple "object" that is backed by a dictionary with string
keys. It will solve this problem by also allowing those name/values to be accessed using field accessing syntax.
You already know the upsides, but this approach has downsides as well that come in the form of marginally less performance than a dictionary and lack of compile-time type checking. You should use it when it will increase readability in certain circumstances where you would otherwise use a dictionary.
Coding this Mess
Since you already know how to use it from above, we'll focus on how I made it. The idea here is simple. We derive from DynamicObject
and then implement a dictionary interface on top of it. All that does is override TryGetMember()
and TrySetMember()
and delegate to an inner dictionary. The dictionary members also forward to the inner dictionary. It's all very simple. I won't show all of the code, but I'll show the part that makes the magic of DynamicDictionary
work:
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
T res;
if (_inner.TryGetValue(binder.Name, out res))
{
result = res;
return true;
}
result = null;
return false;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
_inner[binder.Name] = (T)value;
return true;
}
Where T
above is the type of values the dictionary holds - the key is always a string.
Using it is simple, and already described above but here's some of the example code - there's more in the included project, including a T4 template for demonstration purposes:
dynamic obj = new DynamicDictionary<object>();
obj.test1 = "foo";
obj["test2"] = "bar";
obj.test3 = 100;
Console.WriteLine("test1 = " + obj.test1);
Console.WriteLine("test2 = " + obj["test2"]);
Console.WriteLine("test3 = " + obj["test3"]);
Note that above, both accessing as a dynamic object and as a dictionary are shown. These objects support either or, just like JavaScript. The magic here is the dynamic
keyword, which tells the C# compiler to create a dynamic "call site" where member access is late bound - at runtime instead of compile time. Now you can simply access the object as usual, the exception being there is no Intellisense (autocompletion) in your IDE.
You can construct one of these dynamic objects in your codebehind, and then use them in your ASP.NET pages or T4 templates.
History
- 13th May, 2020 - Initial submission