Skip to main content

Poor Man's Singleton Methods via Dynamic Wrappers in C#

image "The static world you see there is not real, you are programmed to think so. There is a true world out there, which is very very dynamic" - Do I sound like Morpheus in Matrix?


Justin recently wrote an emotional post about Ruby, and as a primary C# guy, I found it quite interesting. Though I’ve never paid some serious attention to Ruby earlier, I was exploring the dynamic features in C# for some time (See my posts on dynamic and also have a look at this ElasticObject implementation). So, I started digging into Ruby a bit after reading Justin’s post, I found a lot of interesting concepts, for example, the Singleton methods.

Singleton Methods

So, what are Singleton methods?

The behavior of an instance is determined by its class, but there may be times we know that a particular instance should have special behavior. In most languages, we must go to the trouble of defining another class, which would then only be instantiated once. In ruby we can give any object its own methods.

And here is a Ruby example.

ruby> class SingletonTest
    |   def size
    |     25
    |   end
    | end
   nil
ruby> test1 = SingletonTest.new
   #<SingletonTest:0xbc468>
ruby> test2 = SingletonTest.new
   #<SingletonTest:0xbae20>
ruby> def test2.size
    |    10
    | end
   nil
ruby> test1.size
   25
ruby> test2.size
   10

See that you are 're-opening' the size method of test2 object, to return some other value other than the value specified by the default size method, at runtime. Isn’t that interesting? For sure, especially if you hasn't visited Ruby earlier.

Poor man's Singleton Methods In C#

Now, I started thinking about implementing something similar in C#, leveraging the dynamic features, with out depending on the traditional AOP style, and came up with a dynamic wrapper that’ll allow you to do wrap objects, some what like a proxy. You can assign a new delegate instance against an existing method name, and the wrapper is capable of re-routing invocations to the assigned method when an invocation happens. Ah, I think some code is better than the explanation.

For example, consider this code.

class Program
    {
        static void Main(string[] args)
        {

            //Existing objects
            Duck someObject = new Duck();
            dynamic duck = someObject.Extend();

            //Call Walk
            duck.Walk();

            //Now modify this Walk() on the fly
            duck.Walk = new Action(() => System.Console.WriteLine("Duck Walking left"));

            //Call Walk again
            duck.Walk();

        }
    }
    public class Duck
    {
        public void Walk()
        {
            System.Console.WriteLine("Duck walking right");
        }
    }
You can see that we are modifying the Walk behaviour, and imagine the output you'll get.

Duck Walking right
Duck Walking left

As you might imagine, the Extend extension method simply creates a dynamic wrapper on top of our duck object, and returns the wrapper for further operations. The wrapper can also wrap static methods, which means you can do something like this as well.

//Static classes
            dynamic con = typeof(System.Console).Extend();
            con.WriteLine=new Action<string>
                             (s=>System.Console.WriteLine("hello " + s));
            con.WriteLine(" world");
            
           //Your output will be 'hello world' (with out the quotes)

The only problem here is, once you extend the object via the dynamic wrapper, you need the whole infrastructure to be dynamic to leverage this, while in AOP your proxies are still typed. So assuming your program universe has two worlds, say static and dynamic, the wrapped object is of no use in the static world – all this will work only in the dynamic world (say your functions/properties accepting dynamic objects and returning dynamic objects etc).

Also, comparing to Ruby, we are not even near - we are not touching the actual object or modifying any behavior of the same, we are just wrapping it :(

Now, if you don't need to wrap existing classes/objects in the .NET framework, you may use the ExpandoObject to attach your own behavior

Another interesting thought


The wrapper can be used to wrap the C# objects, and pass the same to dynamic worlds so that the behavior of your C# objects can be modified there - like, when you pass an object from C# to IronRuby. I havn't tried it yet and I have no idea how it works in the IronRuby world right now, but it should be possible. :)

The Code - Exploring further

So, here are the extension methods and the wrapper, that'll achieve what I showed above.

//Warning: Just wrote this pretty quickly, only for demo purposes :)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Dynamic;
using System.Reflection;

namespace DynamicLibrary
{

 public static class DynamicExtensions
    {
        //Our generic IsGreaterThan extension method
        public static dynamic Extend<T>(this T obj)
        {
            return new ExtensionWrapper(obj);
        }

        public static dynamic New<T>(this T t)  where T:new()
        {
            return new ExtensionWrapper(new T());
        }

    }

    public class ExtensionWrapper : DynamicObject
    {

        /// <summary>
        /// The object we are going to wrap
        /// </summary>
        object _wrapped;

        /// <summary>
        /// A collection of methods
        /// </summary>
        Dictionary<string, Delegate> _methods = new Dictionary<string, Delegate>();

        /// <summary>
        /// Specify the flags for accessing members
        /// </summary>
        static BindingFlags flags = BindingFlags.Instance
            | BindingFlags.Static | BindingFlags.Public;

        /// <summary>
        /// Create a simple private wrapper
        /// </summary>
        public ExtensionWrapper(object o)
        {
            _wrapped = o;
        }


        public ExtensionWrapper(Type t)
        {
            _wrapped = t;
        }


        Type WrappedType
        {
            get
            {
                return (_wrapped is Type) 
                    ? _wrapped as Type 
                    : _wrapped.GetType();
            }
        }

        /// <summary>
        /// Try invoking a method
        /// </summary>
        public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
        {
            var types = from a in args
                        select GetActualType(a);
            string mname = GetInternalName(binder.Name, args);

            if (_methods.ContainsKey(mname))
            {
                result = _methods[mname].DynamicInvoke(args);
                return true;
            }

            var method = WrappedType.GetMethod
                (binder.Name, flags, null, types.ToArray(), null);

            if (method == null)
                return base.TryInvokeMember(binder, args, out result);
            else
            {
                result = method.Invoke(_wrapped, args);
                return true;
            }
        }

        public Type GetActualType(object t)
        {
            return (t is ParameterInfo)
                        ? (t as ParameterInfo).ParameterType : t.GetType();
        }

        /// <summary>
        /// Get the internal name for a method for housekeeping
        /// </summary>
        private string GetInternalName(string name, object[] args)
        {

               var typeNames = from a in args
                            select GetActualType(a).Name;

            string mname = name + "$" +
                                        (typeNames.Count() > 0
                                            ? typeNames.Aggregate((a, b) => a + b)
                                            : string.Empty);
            return mname;
        }

        /// <summary>
        /// Tries to get a property or field with the given name
        /// </summary>
        public override bool TryGetMember(System.Dynamic.GetMemberBinder binder, out object result)
        {
            //Try getting a property of that name
            var prop = WrappedType.GetProperty(binder.Name, flags);

            if (prop == null)
            {
                //Try getting a field of that name
                var fld = WrappedType.GetField(binder.Name, flags);
                if (fld != null)
                {
                    result = fld.GetValue(_wrapped);
                    return true;
                }
                else
                    return base.TryGetMember(binder, out result);
            }
            else
            {
                result = prop.GetValue(_wrapped, null);
                return true;
            }
        }

        /// <summary>
        /// Tries to set a property or field with the given name
        /// </summary>
        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            var prop = WrappedType.GetProperty(binder.Name, flags);
            if (prop == null)
            {
                var fld = WrappedType.GetField(binder.Name, flags);
                if (fld != null)
                {
                    fld.SetValue(_wrapped, value);
                    return true;
                }
                else if (value is Delegate)
                {
                    var param = (value as Delegate).Method.GetParameters();
                    var types = from a in param
                                select GetActualType(a);
                    var method = WrappedType.GetMethod
                                        (binder.Name, flags, null, types.ToArray(), null);

                    if (method != null)
                    {
                        string mname = GetInternalName(binder.Name, param);                         
                        _methods[mname] = value as Delegate;
                        return true;

                    }
                    else
                    {
                        return base.TrySetMember(binder, value);
                    }

                }
                else
                    return base.TrySetMember(binder, value);
            }
            else
            {
                prop.SetValue(_wrapped, value, null);
                return true;
            }
        }

    }
}

This might be insane and of no use, but never mind. Happy coding!! Have a look at my other posts on C# dynamic features

Popular posts from this blog

Top 7 Coding Standards & Guideline Documents For C#/.NET Developers

Some time back, I collated a list of 7 Must Read, Free EBooks for .NET Developers, and a lot of people found it useful. So, I thought about putting together a list of Coding Standard guidelines/checklists for .NET /C# developers as well.As you may already know, it is easy to come up with a document - the key is in implementing these standards in your organization, through methods like internal trainings, Peer Reviews, Check in policies, Automated code review tools etc. You can have a look at FxCop and/or StyleCop for automating the review process to some extent, and can customize the rules based on your requirements.Anyway, here is a list of some good Coding Standard Documents. They are useful not just from a review perspective - going through these documents can definitely help you and me to iron out few hidden glitches we might have in the programming portion of our brain. So, here we go, the listing is not in any specific order.1 – IDesign C# Coding StandardsIDesign C# coding stand…

Hack Raspberry Pi – How To Build Apps In C#, WinForms and ASP.NET Using Mono In Pi

Recently I was doing a bit of R&D related to finding a viable, low cost platform for client nodes. Obviously, I came across Raspberry Pi, and found the same extremely interesting. Now, the missing piece of the puzzle was how to get going using C# and .NET in the Pi. C# is a great language, and there are a lot of C# developers out there in the wild who are interested in the Pi.In this article, I’ll just document my findings so far, and will explain how develop using C# leveraging Mono in a Raspberry Pi. Also, we’ll see how to write few minimal Windows Forms & ASP.NET applications in the Pie as well.Step 1: What is Raspberry Pi?Raspberry Pi is an ARM/Linux box for just ~ $30. It was introduced with a vision to teach basic computer science in schools. How ever, it got a lot of attention from hackers all around the world, as it is an awesome low cost platform to hack and experiment cool ideas as Pi is almost a full fledged computer.  More About R-Pi From Wikipedia.The Raspberry Pi

5 Awesome Learning Resources For Programmers (To help you and your kids to grow the geek neurons)

Happy New Year, this is my first post in 2012. I’ll be sharing few awesome learning resources I’ve bookmarked, and will be pointing out some specific computer/programming related courses I've found interesting from these resources.Also, thought about saving this blog post for my kids as well - instead of investing in these Child education schemes (though they are too small as of today, 2 years and 60 days respectively ). Anyway, personally my new year resolution is to see as much videos from this course collections (assuming I can find some free time in between my regular job && changing my babies diapers).1 – Khan AcademyAs I mentioned some time back, you and your kids are missing some thing huge if you havn’t heard about Khan Academy.  It is an awesome learning resource, especially if you want to re-visit your basics in Math, Science etc.With a library of over 2,600 videos covering everything from arithmetic to physics, finance, and history and 268 practice exercises, th…