Thursday, July 14, 2011

Testing for existence of key in a .NET 4 Dynamic Dictionary

Recently I had to implement a component that recieves a dictionary filled with user settings. I decided to use C# 4's new dynamic keyword to enhance access to the dictionary. After some googling i found a basic implementation of DynamicDictionary (Thanks to Phil Haack ).

The one flaw in the implementation can be observed by looking at the code below. If key "CustomerName" is not in the dictionary an exception will be thrown.

dynamic dic = new DynamicDictionary();

string customerName = string.Empty;
            
customerName = dic.CustomerName; // Potential BinderException Here 

I wanted a clean approach to testing for existence of a key in my DynamicDictionary like in the code below:
 
dynamic dic = new DynamicDictionary();

string customerName = string.Empty;

if (dic.HasCustomerName())
  customerName = dic.CustomerName;

I extended Phil's DynamicDictionary code to support a function with signature of  "bool Has[Key]()". To implement this I had to override  TryInvokeMember method of the DynamicObject class, in which I strip out the "Has" part and simply call ContainsKey([Key]) on the dictionary.
Here is the complete code:

  public class DynamicDictionary : DynamicObject
    {
        Dictionary<string, object>
          _dictionary = new Dictionary<string, object>();

        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            _dictionary[binder.Name] = value;
            return true;
        }

        public override bool TryGetMember(GetMemberBinder binder,
            out object result)
        {
            return _dictionary.TryGetValue(binder.Name, out result);
        }

        public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
        {
            result = false;

            if (binder.Name.StartsWith("Has"))
            {

                var propName = binder.Name.Substring(3, binder.Name.Length - 3);

                result = _dictionary.ContainsKey(propName);

                return true;
            }



            return false;

        }
    }