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:
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 :-)