Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Creating a Simple Dynamic Dictionary in C#

2.86/5 (8 votes)
13 May 2020MIT2 min read 37.3K   241  
This tip shows how to create a dynamic JavaScript-like object to be used in web pages and T4 templates.
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:

ASP.NET
<%= obj["foo"] %>

What we really want is:

ASP.NET
<%= 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:

C#
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:

C#
// set some values
dynamic obj = new DynamicDictionary<object>();
obj.test1 = "foo";
obj["test2"] = "bar";
obj.test3 = 100;

// get some values
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

License

This article, along with any associated source code and files, is licensed under The MIT License