You can do this by storing a reference to the previously retrieved object, or Dictionary, when TryGetValue
is called. I use a class that looks like the following:
public DynamicFile(IDictionary<string, object> dictionary)
{
if (dictionary == null)
throw new ArgumentNullException("dictionary");
_dictionary = dictionary;
_lastGetRef = _dictionary;
}
private readonly IDictionary<string, object> _dictionary;
private IDictionary<string, object> _lastGetRef;
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (!_dictionary.TryGetValue(binder.Name, out result))
{
result = null;
return true;
}
var dictionary = result as IDictionary<string, object>;
if (dictionary != null)
{
result = new DynamicFile(dictionary);
_lastGetRef = dictionary;
return true;
}
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
if(_dictionary.ContainsKey(binder.Name))
_dictionary[binder.Name] = value;
else if (_lastGetRef.ContainsKey(binder.Name))
_lastGetRef[binder.Name] = value;
else
_lastGetRef.Add(binder.Name, value);
return true;
}
_dictionary
is set by the constructor when the dynamic object is created and is then set as the immediate last reference dictionary. This works due to the fact that Dictionarys are classes and hence reference types.
To then nest correctly, you need to instantiate each dictionary at each nest level just like a multi-dimensional array. For example:
myexpando.somelist = new Dictionary<string, object>();
myexpando.somelist.anotherlist = new Dictionary<string, object>();
myexpando.somelist.anotherlist.someitem = "Hey Hey There! I'm a nested value :D";
You could probably write some code in TryGetMember
that automatically adds a Dictionary when the key doesn't exist, but I didn't need that so I didn't add it.