C# Callback and Event Mechanisms
Often when you instantiate an object, you then control everything about that entity throughout its lifecycle. This works well in that it enables you to have full control over the operation of your objects. However, it has a slightly darker side in that you are tasked with writing code that monitors what is often a large number of independent objects. In effect, your code is spending a lot of its time managing itself rather than solving the domain-specific problem it was written to solve! This sounds a bit like the tail wagging the dog. A better approach is for your objects to be able to autonomously inform you of state changes as and when they occur. This frees you to add more domain-specific smarts to your code. Properly implemented, this can produce more loosely coupled solutions and better separation of concerns.
Callback mechanisms allow you to equip objects with enough intelligence to inform you when they need attention or when some important event has occurred. C# has a range of callback mechanisms, all of which are relatively simple to master. This reflects the upsurge in popularity of the client-side and server-side programming model. It's simply no longer economical or necessary to write code that has to check the status of objects which are potentially distributed across many machines. Another side to this is the huge numbers of small, resource-constrained computing devices in use. The code that runs on these devices must be as small and as responsive as possible. So, this topic isn't just of academic interest!
To describe the C# callback and event mechanisms, I'll continue to use the example (from my earlier article, "C# and IT Management Infrastructure") of LSPs (or label switched paths). As discussed in the earlier article, LSPs are basically pre-defined paths through a network that implement a technology called MPLS (Multiprotocol Label Switching). My previous article used C# delegates for event management. In this one, I'll use the lower-level C# callback interface approach and then compare and contrast the two.
By now, it's probably no surprise to my loyal readers that I continue to use the open source SharpDevelop IDE (Integrated Development Environment) product. The boom in open source development reflects the trend among modern organizations such as Google to allow programmers some free time each week to contribute to pet projects. This is a great development in that such software is then freely available. It also helps the programmers to have a break and to not get too bogged down in the domain specifics of their paid work. The programmers and designers also get to mix with peers, and exchange ideas and code. We can all get a bit stale just focusing on the problems of day-to-day work!
Open source is moving software technology in interesting directions. One take on this movement is that it is in a sense creating a software equivalent to the Internet itself! Nobody owns the open source code, but everyone can download and use it. Maybe this is the only way of breaking the hegemony of organizations such as Microsoft and creating truly open software. Probably, in ten years’ time we'll look back and wonder how we ever got by without open source software!
Much of the open source code I've used has been surprisingly good. In many cases, such products can be both innovative and of high quality. Usually, the rough edges are in the installation/documentation/support areas—not many people volunteer for those areas! Still, this is a young area. The important issue is that all this open source code comes for free! Amazing.
As usual, Listing 1 shows a sneak preview of the finished C# code, where:
- I create an LSP.
- I create an event sink.
- I attach the event sink to my LSP object.
- I forward some data across the LSP to cause state changes.
Listing 1 The Finished C# Code
// Instantiate an LSP Lsp lsp = new Lsp("LSP123", 1, 5, "R2R3R4R5", 100, 150); // Make sink object. Console.WriteLine("Creating LSP event sink\n"); LspEventSink sink = new LspEventSink("Event sink"); // Attach the sink to the LSP. Console.WriteLine("Attaching a sink to the LSP"); lsp.Attach(sink); // Forward some blocks of data (to generate some events.) Console.WriteLine("\n***** Forwarding data *****"); for (int i = 0; i < 3; i++) lsp.ForwardSomeData(20);
You'll next see the way the use of events allows for a useful level of decoupling between the event code and the LSP code.