Using a ServiceContainer with Delegates - Truly Simple Services

While working with a colleague on a project I got into a debate about event-handling versus delegates stuffed into a service container. It sounded weird to me at the time; I've always been a huge fan of event-driven programming so I tend to lean that way when I need to make my objects responsive to one another. The way my colleague looks at it, "everything's a service, so if you just add your methods that you need to run to your service container you can call them when you need them." The idea seemed truly nutty to me so I just had to code it up. It is important to note here that our system already made use of the ServiceContainer approach. We have a custom service container that our applications use; in this way we can add any service to the container at run-time and provide our whole application (and all of it's components) with access to everything via the service container. If you're not familliar with that approach this may seem a little off-kilter. 

First thing I did was to create a custom ServiceContainer implementation. The code for my GenericServiceContainer is below. Note the extra method I've added which makes use of generic types. 

 

public class GenericServiceContainer : System.ComponentModel.Design.ServiceContainer
{
  public virtual T GetService<T>() where T : class
  {
    return this.GetService(typeof(T)) as T;
  }
}

Next, I'll create a few delegate types. In this way, any class that has knowledge of these delegate types can request the GSC send'em out.

public delegate void MessageDelegate(string message);
public delegate int AdditionDelegate(int x, int y);

 

Though the functionality abstracted in the form of delegates I still need to create a class that can "do the work" for the application. To accomplish this I've written a simple WorkerClass, the code for which is below.

public class WorkerClass
{
  public static void ShowMessage(string message)
  {
    Console.WriteLine(message);
  }
  
  public static int Add(int x, int y)
  {
    return (x + y);
  }
}


Finally, some tests will prove the theory.  

[TestFixture]
public class TestServiceContainer
{
  GenericServiceContainer _container;
  
  [SetUp]
  public void Setup()
  {
    _container = new GenericServiceContainer();
    _container.AddService(typeof(MessageDelegate),
      new MessageDelegate(WorkerClass.ShowMessage));
      
    _container.AddService(typeof(AdditionDelegate),
      new AdditionDelegate(WorkerClass.Add));
  }
  
  [TearDown]
  public void TearDown()
  {
    _container.Dispose();
  }
  
  [Test]
  public void TestMessageDelegate()
  {
    MessageDelegate del = _container.GetService<MessageDelegate>();
    Assert.IsNotNull(del);
    del.Invoke("Testing");
  }
  
  [Test]
  public void TestAdditionDelegate()
  {
    AdditionDelegate del = _container.GetService<AdditionDelegate>();
    Assert.IsNotNull(del);
    int result = del.Invoke(2, 2);
    Assert.AreEqual(result, (2 + 2));
  }
}

 

So that's it! With this code I've defined the structure of the methods that will be doing the work and allowed redirection to a worker class to perform the work. Now, any class within the application being augmented by my custom ServiceContainer can have easy access to centralized functionality.

Happy Coding!