Michael Wild
Michael Wild

Reputation: 26381

Dynamically add property on read-access to DynamicObject or ExpandoObject

I have a use-case where I would need to add properties to a dynamic object in C# on reading, as opposed to writing. I.e. something like this:

class Foo : DynamicObject
{
   private readonly Dictionary<string, object> _properties = new Dictionary<string, object>();

   public override bool TryGetMember(GetMemberBinder binder, out object result)
   {
       if (!_properties.TryGetValue(binder.Name, out result)
       {
           result = object();
           _properties.Add(binder.Name, result);
       }
       return true;
   }
}

class Test
{
    public void Bar()
    {
        var o = new Foo();
        // Fails!
        var prop = o.SomeProperty;
    }
 }

The end-goal is to use this shim in LINQ expressions. I don't actually care for the value that is returned, all I want is for a convenient way to record the fact that the property has been accessed and then use that later when inspecting the expression tree.

Is this even possible with C#?

Upvotes: 1

Views: 495

Answers (1)

Vladimir Mezentsev
Vladimir Mezentsev

Reputation: 918

I don't actually see trouble here. Tried it and result is quite as expected: Just added Properties property to get actual dictionary;

class Foo : DynamicObject {
    private readonly Dictionary<string, object> _properties = new Dictionary<string, object>();

    public Dictionary<string, object> Properties {
        get { return _properties; }
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result) {
        if (!_properties.TryGetValue(binder.Name, out result)) {
            result = new object();
            _properties.Add(binder.Name, result);
        }
        return true;
    }
}

now usage:

dynamic o = new Foo();
var prop = o.SomeProperty;
var prop2 = o.SomeNewProperty;
var allAccessedPropNames = o.Properties.Keys;

And allAccessedPropNames will result as {"SomeProperty", "SomeNewProperty"}

If you remove Add line from TryGetMember then it results with empty collection.

Upvotes: 2

Related Questions