Delegate Chaining

After a few questions I have taken part in, I have recently gone further into delegate chaining.  I have to say that I am, like most others things in C#, really impressed.  It kind of adds a horde of functionality to the facade design pattern.  So I thought up a totally useless implementation of it to try and get some design ideas for deep usage.  What I did was:

  • Create a UnitOfWork Class.
    • This class accepts delegates. The method signature requires methods which returns boolean and accepts one parameter of type string.
    • It records all methods which return false after invocation.
    • It records all methods and an inaccurate stopwatch (lol, as I later found out) to measure the length of time the invocation took.
  • A Pair Class which I blogged about previously today.
    • The difference I have added this time was to enable the first and second object to be of different types.
  • A Stopwatch class
  • Four static methods which meet the signature of the UnitOfWork delegate.

The output of this useless program, lol, is shown below:

image

Note the 102 milliseconds.  This is why I say "inaccurate stopwatch lol."

Classes

 

UnitOfWork

Hide Code [-]
    public class UnitOfWork
    {
        public delegate bool UnitOfWorkDelegate(string unitName);

        public UnitOfWorkDelegate chain = null;

        private List<UnitOfWorkDelegate> workUnitsNotNeeded;

        private List<Pair<UnitOfWorkDelegate, TimeSpan>> workuntiSpeedTests;

        private TimeSpan finish;

        public UnitOfWork()
        {
            workUnitsNotNeeded = new List<UnitOfWorkDelegate>();
            workuntiSpeedTests = new List<Pair<UnitOfWorkDelegate, TimeSpan>>();
        }

        public void AddUnitOfWork(UnitOfWorkDelegate unitOfWork)
        {
            chain += unitOfWork;
        }

        public void RemoveUnitOFWork(UnitOfWorkDelegate unitOfWork)
        {
            chain -= unitOfWork;
        }

        public void RunUnitOfWork()
        {
            StopWatch watch = new StopWatch();

            foreach (UnitOfWorkDelegate unit in chain.GetInvocationList())
            {
                watch.Start();

                if (!unit.Invoke("The Unit of Work Class"))
                {
                    finish = watch.Finsh();
                    workUnitsNotNeeded.Add(unit);
                }

                workuntiSpeedTests.Add(new Pair<UnitOfWorkDelegate, TimeSpan>(unit, finish));
            }
        }

        public void OutputStatus()
        {
            Console.WriteLine();

            Console.WriteLine("The following methods returned false");

            Console.WriteLine();

            foreach (UnitOfWorkDelegate u in workUnitsNotNeeded)
            {
                Console.WriteLine(u.Method.Name);
            }

            Console.WriteLine();

            Console.WriteLine("The following speeds where recorded for each methods' invocation");

            Console.WriteLine();

            foreach (Pair<UnitOfWorkDelegate, TimeSpan> p in workuntiSpeedTests)
            {
                Console.WriteLine("Method Name : {0} [ Completed in {1} millseconds ]", p.First.Method.Name, p.Second.TotalMilliseconds);
            }
        }
    }
{..} Click Show Code

 

StopWatch

Hide Code [-]
    public class StopWatch
    {
        private DateTime m_start;
        private DateTime m_finish;

        public void Start()
        {
            m_start = DateTime.Now;
        }

        public TimeSpan Finsh()
        {
            return DateTime.Now - m_start;
        }
    }
{..} Click Show Code

Updated Pair Class

Hide Code [-]
    public class Pair<T, S>
    {
        private T m_first;

        private S m_second;

        public Pair(T first, S second)
        {
            m_first = first;
            m_second = second;
        }
        public T First
        {
            get { return m_first; }
            set { m_first = value; }
        }

        public S Second
        {
            get { return m_second; }
            set { m_second = value; }
        }
    }
{..} Click Show Code

The Program and the four static methods

Hide Code [-]
    public class Program
    {
        static void Main(string[] args)
        {
            UnitOfWork newUnitOfWork = new UnitOfWork();

            newUnitOfWork.AddUnitOfWork(Operation1);
            newUnitOfWork.AddUnitOfWork(Operation2);
            newUnitOfWork.AddUnitOfWork(Operation3);
            newUnitOfWork.AddUnitOfWork(Operation4);

            newUnitOfWork.RunUnitOfWork();

            newUnitOfWork.OutputStatus();

            Console.ReadLine();
        }

        static bool Operation1(string name)
        {
            Console.WriteLine(name);
            System.Threading.Thread.Sleep(100);
            return false;
        }

        static bool Operation2(string name)
        {
            Console.WriteLine(name);
            System.Threading.Thread.Sleep(200);
            return true;
        }

        static bool Operation3(string name)
        {
            Console.WriteLine(name);
            System.Threading.Thread.Sleep(300);
            return false;
        }

        static bool Operation4(string name)
        {
            Console.WriteLine(name);
            System.Threading.Thread.Sleep(400);
            return true;
        }
    }
{..} Click Show Code

So basically what I am trying to convey, all be it rather badly, is the power of chaining delegates.  I am =thinking of different ways to achieve things here, and their uses. I would love to know also how, if possible (which I am sure it is), to dynamically append method invocations to existing methods at runtime using reflection!  That would be very handy.

 

Another one of my memory dumps! lol

Cheers,

Andrew :-)

Published Thursday, April 24, 2008 3:23 PM by REA_ANDREW
Filed under: ,

Comments

# re: Delegate Chaining

Tuesday, May 06, 2008 7:52 AM by Jorge Córdoba

Why are you using your own StopWatch class instead of the more reliable .NET StopWatch class (msdn.microsoft.com/.../system.diagnostics.stopwatch.aspx)??

About what you mention about appending methods at runtime, I do it (must) on a Plugin Library I've been working on (www.thealphasite.org/.../Monet). Documentation and comments are in Spanish (sorry but that's my native language :P) but code should be clear enough.

The section you would most likely be interested in is located in the PluginManager.cs in the ProcessHooks method. The library allows you to define "Hooks" wich are methods ment to be inserted into the chain of calls of a given Hookable event so the plugin manager have to chain them using reflection in runtime. The library is LGPL so feel free to play around (also is alpha so be careful).

Hope it helps

Leave a Comment

(required) 
(required) 
(optional)
(required)