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() 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();
    Assert.IsNotNull(del);
    del.Invoke("Testing");
  }
  
  [Test]
  public void TestAdditionDelegate()
  {
    AdditionDelegate del = _container.GetService();
    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! 

Brady Gaster
Hi! I'm a christian dad who lives near Seattle, where I work with the talented folks at Microsoft to create compelling demonstrations for conferences that instruct and inspire developers who want to party in the cloud.