Nesting a private C# Dynamic object

I don’t use often the dynamic feature of the C# language, but past yesterday I bumped against a subtle issue.

A basic implementation.

Consider a very basic dynamic object implementation against the DynamicObject, which looks like the overhauled ExpandoObject:

    public class MyDynamicObject
        : DynamicObject
    {
        public MyDynamicObject()
        {
            this._dict = new Dictionary<string, object>();
        }


        private readonly Dictionary<string, object> _dict;


        /**
         * called when the host tries to GET the value
         * from a member
         **/
        public override bool TryGetMember(
            GetMemberBinder binder,
            out object result
            )
        {
            //look for the member into the dictionary
            bool found = this._dict.TryGetValue(
                binder.Name,
                out result
                );

            if (found)
            {
                return true;
            }

            //yield the default behavior
            return base.TryGetMember(
                binder,
                out result
                );
        }


        /**
         * called when the host tries to SET a value
         * against a member
         **/
        public override bool TrySetMember(
            SetMemberBinder binder,
            object value
            )
        {
            //store the value in the dictionary
            this._dict[binder.Name] = value;
            return true;
        }

    }

Its usage may be expressed as follows:

    class Program
    {
        static void Main(string[] args)
        {
            dynamic d = new MyDynamicObject();
            d.first = "John";
            d.last = "Doe";
            d.birthdate = new DateTime(1966, 7, 23);
            d.registered = true;

            Console.WriteLine(d.first);
            Console.WriteLine(d.last);
            Console.WriteLine(d.birthdate);
            Console.WriteLine(d.registered);

            Console.ReadKey();
        }
    }

So far, so well. But what about retrieving a member “by name”, that is using a string as a “key” for mapping the desired member?
The above snippet could be refined as follows:

    class Program
    {
        static void Main(string[] args)
        {
            dynamic d = new MyDynamicObject();
            d.first = "John";
            d.last = "Doe";
            d.birthdate = new DateTime(1966, 7, 23);
            d.registered = true;

            Console.WriteLine(d.first);
            Console.WriteLine(d.last);
            Console.WriteLine(d.birthdate);
            Console.WriteLine(d.registered);

            Console.WriteLine();
            Console.Write("Please enter a field name: ");
            string key = Console.ReadLine();

            //how to map the required field?
            //Console.WriteLine("The field value is: " + ??? );

            Console.ReadKey();
        }
    }

Again, with an ExpandoObject everything would be straightforward, but the actual “MyDynamicObject” used in the original application requires a more complex content, with XML and a dictionary working aside.

pic1

Going on this way, the “keyed” dynamic object implementation is easy to refine:

    public class MyDynamicObject
        : DynamicObject
    {

        // ... original implementation ...


        /**
         * provide a member access through a key
         **/
        public object this[string key]
        {
            get { return this._dict[key]; }
            set { this._dict[key] = value; }
        }

    }

At this point, the demo application works fine with both the accessing way. It looks much like a JavaScript object!

    class Program
    {
        static void Main(string[] args)
        {
            dynamic d = new MyDynamicObject();
            d.first = "John";
            d.last = "Doe";
            d.birthdate = new DateTime(1966, 7, 23);
            d["registered"] = true;

            Console.WriteLine(d.first);
            Console.WriteLine(d.last);
            Console.WriteLine(d.birthdate);
            Console.WriteLine(d.registered);

            Console.WriteLine();
            Console.Write("Please enter a field name: ");
            string key = Console.ReadLine();

            Console.WriteLine("The field value is: " + d[key]);
            Console.ReadKey();
        }
    }

pic2

The problem: a nested-private dynamic object.

Consider a proxy pattern, and a dynamic object to expose indirectly to the hosting application. Also consider that the dynamic object should be marked as “private” due to avoid any possible usage outside its context.
The revised component would look as follows:

    class MyClass
    {

        public IDynamicMetaObjectProvider GetDynamicAccess()
        {
            return new MyDynamicObject();
        }


        //notice that the below class is marked as "private"
        private class MyDynamicObject
            : DynamicObject
        {

            // ... implementation as the keyed-one seen above ...

        }
    }

When used in such a sample application, it won’t work:

    class Program
    {
        static void Main(string[] args)
        {
            var c = new MyClass();

            dynamic d = c.GetDynamicAccess();
            d.first = "John";
            d.last = "Doe";
            d.birthdate = new DateTime(1966, 7, 23);
            d["registered"] = true;     //throws!

            Console.WriteLine(d.first);
            Console.WriteLine(d.last);
            Console.WriteLine(d.birthdate);
            Console.WriteLine(d.registered);

            Console.WriteLine();
            Console.Write("Please enter a field name: ");
            string key = Console.ReadLine();

            //the following would also throw
            Console.WriteLine("The field value is: " + d[key]);
            Console.ReadKey();
        }
    }

Better: it won’t work the “keyed” access, but the classic way is available, however.

I wasn’t able to find *ANY* solution unless you have the ability to modify the implementation. Here are the possible solutions.

Solution 1: mark the MyDynamicObject class accessor as “public”.

This is the simplest way, but I’d say it’s also a NON-solution because the original desire is keeping the class as “private”.

Solution 2: use the reflection.

You know, reflection is able to dig into the deepest yet hidden corners of your assembly, but it’s yet a last-rescue way. The compiler has a very-little (or nothing at all) control over what we access through reflection. I’d discourage, though feasible.

Solution 3: add an interface.

The “best” solution (although I’d demote to “decent”) is adding an interface, which aim is to expose the indexed access (keyed) to the host application.

    interface IKeyedAccess
    {
        object this[string name] { get; set; }
    }


    class MyClass
    {

        public IDynamicMetaObjectProvider GetDynamicAccess()
        {
            return new MyDynamicObject();
        }


        //notice that the below class is marked as "private"
        private class MyDynamicObject
            : DynamicObject, IKeyedAccess
        {

            // ... implementation as the keyed-one seen above ...

        }
    }

Our keyed-dynamic object must implement the interface, but rather obvious because our primary goal is that.
The major difference is rather on the object usage:

    class Program
    {
        static void Main(string[] args)
        {
            var c = new MyClass();

            dynamic d = c.GetDynamicAccess();
            var dk = (IKeyedAccess)d;
            d.first = "John";
            d.last = "Doe";
            d.birthdate = new DateTime(1966, 7, 23);
            dk["registered"] = true;

            Console.WriteLine(d.first);
            Console.WriteLine(d.last);
            Console.WriteLine(d.birthdate);
            Console.WriteLine(d.registered);

            Console.WriteLine();
            Console.Write("Please enter a field name: ");
            string key = Console.ReadLine();

            Console.WriteLine("The field value is: " + dk[key]);
            Console.ReadKey();
        }
    }

Unfortunately not as good as expected, but at least it allows to keep sticky to the “private” constraint.

Here is the source code.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s