In the last issue of CODE Magazine, I introduced you to creating dynamic lambda expressions (Simplest Thing Possible: Dynamic Lambda Expressions - Part 1). This month, I continue with that theme with one of the most powerful and flexible classes in .NET, the Dictionary. A dictionary in .NET is a list of key value pairs. Since .NET 3, we've had the ability to generically define classes, meaning that we can specify a generic class as to data type and then specify the exact data type when we implement our class in code. In the case of a dictionary, we might choose to have string keys and string values. In that case, our definition would be Dictionary<string,string>. Alternatively, I can implement a dictionary of string keys and integer values: dictionary<string,int>.

What if you don't know until runtime what your value data type will be? To add a further complication to the mix, what if you need to execute dynamic queries against your dictionary? In the last article, the data types for a specific property was fixed. This month, not only are you going to have the flexibility of dynamic queries, you will also have the ability to have multiple data types in the same dictionary. Let's get started.

The Object Class and Data Type

Every class in .NET originates from a single root class named Object. The Object class contains the following methods that are also present via inheritance of all .NET classes:

  • Equals
  • Finalize
  • GetHashCode
  • ToString

To go along with the Object class is the Object data type that holds the address of any object instance. The Object data type can hold any Reference or Value type. For example, if you have an instance of your custom Person class, you could have the following code:

var myPersonInstance = new Person();
object obj = myPersonInstance;

You can also assign any value type to an object (int, double, bool, string, etc.). For example:

object obj;
var myInt = 1;
var myDouble = 2d;
obj = myInt;
obj = myDouble;

Dictionary<string,object>

One of the most powerful .NET classes is the Dictionary. It enforces the uniqueness of a key and has powerful search capabilities via LINQ. The following is an example of a Dictionary<string,object> instance that represents a person and an address:

var person = new Dictionary<string, object>();
person["FirstName"] = "John";
person["LastName"] = "Smith";
person["DOB"] = DateTime.Parse("01/01/1970");
person["Active"] = true;
person["Donations"] = 1500d;
var address = new Dictionary<string, object>();
address["Number"] = "1234";
address["Street"] = "Market Street";
address["City"] = "Philadelphia";
address["State"] = "PA";
address["ZipCode"] = "19101";
person["Address"] = address;

If you rely on JSON.NET (and you probably do!) for your JSON serialization and deserialization, the JSON representation of a mythical person is as follows:

{
    "FirstName": "John",
    "LastName": "Smith",
    "Address": {
        "Number": "1234",
        "Street": "Market Street",
        "City": "Philadelphia",
        "State": "PA",
        "ZipCode": "19101"
    }
}

Without any specifically defined classes, using a string object Dictionary, you can easily represent complex data relationships. The one question you may have is why you would ever want to use this approach, as opposed to static classes. Perhaps you have a use case where you need some dynamic data capabilities. Maybe you're dealing with a Web application that offers some flexibility as to data elements that could be sent back to the server. Instead of having static classes to manage, you might choose to, instead, manage the dynamic data. Does this mean that static classes should be cast to the scrap heap? Of course not. The world is not a nail and dictionaries are not a hammer. Like every approach, there are use cases where this approach will fit and others where it won't fit quite as well. Dynamic data approaches can afford valuable flexibility. We certainly know this from the JavaScript world.

Another question you may have is whether there's a performance hit when dealing with objects, as opposed to the real underlying data type. The answer may be yes. It depends on whether you have to deal with the underlying data types and how often you need to convert the data. In .NET, this is known as boxing and unboxing data. When you have an underlying data type in a generic object, the data is boxed. In other words, the data is wrapped inside the System. Object. The .NET environment still knows what the underlying data type is. For example, if I want the month portion of a DateTime value, I can simply access the Month property. To do that in this case, you have to cast your DateTime value, which is stored as an Object to a DateTime like this:

var month = ((DateTime)person["DOB"]).Month;

This casting doesn't come for free. There's some overhead with it. The question is whether the overhead cost is worth the value in the flexibility with a dynamic structure. That's not a question that can be answered generally. The answer always depends on your specific facts, circumstances, and performance requirements.

A List of Dictionaries

Before I get into dynamic queries, let's extend the example to a list of dictionaries. I'll use the following structure:

var people = new List<Dictionary<string, object>>();

The following is the JSON representation of two people:

[{
    "FirstName": "John",
    "LastName": "Smith",
    "DOB": "1970-01-01T00:00:00",
    "Active": true,
    "Donations": 1500.0,
    "Address": {
        "Number": "1234",
        "Street": "Market Street",
        "City": "Philadelphia",
        "State": "PA",
        "ZipCode": "19101"
    }
}, {
    "FirstName": "Jane",
    "LastName": "Smith",
    "DOB": "1975-01-01T00:00:00"
}]

Notice that, in this case, you have a JSON array and the second person only has a first and last name as well as a date of birth. No other information is available. Because of the dynamic structure, that's OK. It would be fine in a static structure as well. The only difference is that the other items would be null.

Building Dynamic Queries

Now that there are two people in the structure, you can construct some meaningful queries. Using the example, if you know that you will always have a need to test whether a date of birth is less than or equal a specific value, then you don't need to resort to using dynamic queries. A simple example is as follows:

var result = people.AsQueryable().Where(x =>
(DateTime)x.Value["DOB"] <=
DateTime.Parse("7/1/1995"));

Notice that in order to get this query to work, the date of birth element needs to be unboxed. This is because the operation selected cannot be between an object and a datetime value. To get around that problem, you have to cast the object to a compatible data type.

What if you don't know which element or elements could be part of the query? What if any eligible operation could be performed against a data element? One thing is for sure, you can't have a case statement with every possible combination of options. Instead, you need to leverage the techniques I introduced in the last issue. To review, the dynamic queries in the last issue were run against static classes. In this issue, I'll take the same general approach, but this time against a list of string, object dictionaries.

If you haven't read my last column on building dynamic queries, I suggest that you take a break and read that article because I go over the fundamentals of the System.Linq.Expressions Namespace.

The first step is to build the base parameter of the lambda expression:

var parameter = Expression.Parameter(typeof(Dictionary<string,object>), "x");

Remember, the list is made up of string,object dictionaries. Therefore, the lambda parameter is of that type.

In order to query the list of dictionaries, you need a way to interrogate the dictionary values with either a method or property. Because you're using a dictionary, you'll use the item property. The next step is to use reflection to get information on the item property:

var propertyInfo = typeof(Dictionary<string, object>).GetProperty("Item");

Next, you need a constant value that will be compared to a dictionary element. In this case, it will be a DateTime value to compare to the DOB field:

var value = Expression.Constant(
DateTime.Parse("7/1/1995")
);

Next, you have to have a way to reference a dictionary element. In addition, because all of the elements are object values, you need a way to convert to the appropriate data type. The following code handles this task:

var arguments = new List<Expression> {
    Expression.Constant("DOB") };
var index = 
Expression.Convert(Expression.MakeIndex(parameter,
propertyInfo, arguments), typeof(DateTime));

Once you have all of that, you can create the expression and lambda:

var expression = 
Expression.MakeBinary(ExpressionType.LessThanOrEqual,
index, value);
var lambda = Expression.Lambda<Func<Dictionary<string, object>,
bool>>(expression, parameter);

The following is the dynamic lambda's string representation:

{x => (Convert(x.Item["DOB"]) <= 7/1/1995 12:00:00 AM)}

Now, you can use the dynamically generated lambda:

var result = people.AsQueryable().Where(lambda);

If you need to implement additional criteria, you can simply define another expression and then, with an existing expression, invoke the And or Or methods. Leveraging the previous code as an example it looks like this:

expression = Expression.And(expression, newExpression);

Conclusion

The .NET Dictionary class is very powerful and the string, object Dictionary offers great flexibility when dynamic data structures fit your use case. Dictionaries can offer a level of flexibility that static classes don't provide. That's not to say that dictionaries should be used to the exclusion of static classes. You've also seen that queries, both static and dynamic, are easy to generate. When you're looking for flexibility with data in your next project, consider using the string, object Dictionary structure.