Here’s a simple technique you can use to easily eliminate duplicate code. Try not to let the word “delegates” scare you away from learning the technique and I’ll try to refrain from using the word “delegate” as much as possible. I’ll start small and then work my way towards a more complex example that really demonstrates its power.
Before I go any further, I’d like to point out that my post about Using IDisposable objects responsibly contains a more extravagant example of how this technique is useful. This post goes further to explain HOW we use the technique.
A simple example
Let’s look at two overly simplistic methods that do different things with a connection object. Whereas the yellow code is identical across the two method, the blue and green code illustrates the differences between the two methods.
There may not be much duplicate code here, but that’s not important right now. When thinking about how we can make this code better, consider these things:
- What if we decide one day to use try/catch statements instead of using statements? Doing so would allow us to catch and process specific exception types.
- What if the code required to create the connection changes one day?
- What if there were dozens of places throughout our application where this type of code is used?!?!?!?!
In order to make any of those changes, you’ve got to touch the code in every single place where the pattern exist. That’s the problem we want to fix. We want to be able to make those change, or any other changes, in one place, and have it affect the entire application.
Looking the blue and green code above, you can see that the only dependency those methods have is in the connection object. If you think about it, the blue and green methods don’t care where the connection object comes from or what happens to it afterwards – they just need a connection object. Our code would be much better if we could prevent from showing how the connection object is created or disposed.
So let’s change our two methods to see how we can better accommodate change in our application.
I can just hear my boss complaining about that strange => syntax, but bare with me. :) For the most part, this new code looks the same as our original code. Look back at the first code example to verify the differences between the two. As you’ll soon see, they definitely do the same thing, while, at the same time, providing a great deal more flexibility.
Creating the UsingConnection method
Here’s a different example that, whether you realize it now or not, illustrates the concept. Look at it closely, and then look at the CallIndirectly method even closer. If you can grasp this, the rest is relatively easy.
Here’s the same thing with a bit of color coding to try and help illustrate what’s happening:
Hopefully, you’ve determined that this should be the output of such a program:
In the example above, CallIndirectly takes a method (Action) as a parameter and stores that parameter in a variable called methodToCall. Just as we write WriteHelloWorld() to execute WriteHelloWorld, we write methodToCall() when we want to call the method that was passed to CallIndirectly. You can immediate see from the output of the program that using CallIndirectly provides us with an opportunity to do things both “Before” and “After” our desired method gets called. Essentially, CallIndirectily is a method that calls another method. The trick is, we have to pass a method as a parameter to CallIndirectly so it will know which method to call.
Again, if you can grasp that much, the rest is pretty simple.
UsingConnection is pretty much the exact same thing as Callindirectly. If we wanted to, we could use UsingConnection in the exact same way that we used CallIndirectly above! Here’s proof:
And again with the color coding (let me know if it helps – I’m curious).
What’s that Action stuff?
Notice how the method signatures for DoSomething and DoMoreStuff are identical with the exception of their names.
For our UsingConnection method to work, the first thing we need to do is figure out a way to generalize those signatures. In other words, we need a way of defining a method signature that could have any name (or even no name, as we’ll eventually see), and that takes a single OleDbConnection parameter. We can represent that last statement with Action<OleDbConnection>. You can pretend “Action” represents the name of the method and OleDbConnection represents the first parameter. If our methods took three parameters – An OleDbConnection, OleDbCommand, and an OleDbDataReader, for example, we could represent the method by using Action<OleDbConnection, OleDbCommand, OleDbDataReader>.
I find the easiest way to do this is to imagine placing the words DoSomething and DoMoreStuff with the word Action. What’ you’d then have is:
While that’s close to the desired result, there’s still a bit more we have to do. It turns out, the name of our OleDbConnection parameter isn’t important either, so let’s get rid of that:
Also, the void return type isn’t important to us…
Finally, to really use the Action keyword , we have to replace the ( and ) with < and >. The end result looks like this:
Because UsingConnection takes a parameter of type Action<OleDbConnection>, that tells us we can pass any method to UsingConnection, so long as it takes a single parameter of type OleDbConnection. In other words, just as void DoSomething(OleDbConnection connection) tells us that we can pass an OleDbConnection object to DoSomething, we can see that void UsingConnection(Action<OleDbConnection> action) tells us that we can pass any action (read: method) to UsingConnection so long as the method we’re passing accepts an OleDbConnection parameter.
What about that pesky lambda syntax?
The Test1 and Test2 methods below do the exact same thing, yet it’s apparent that Test2 uses a syntax that isn’t exactly intuitive at first.
To understand that => syntax, let’s expand on our understanding of Action. As you should recall, the Action<OleDbConnection> parameter tells us that we can pass any method to UsingConnection so long as it accepts an OleDbConnection parameter. Okay, so let’s copy/paste the entire contents of our DoSomething method into our call to UsingConnection and see what happens.
Well, that’s basically what we want to do, but it’s obvious that code isn’t going to compile. To make it compile, we only have to make TWO changes.
Remember, Action<OleDbConnection> means that the name of the method and its return type do not matter. So the first thing we can do is remove the void DoSomething part.
The ONLY other thing we have to do now is separate the parameters from the method body with the two characters =>.
That’s technically it. The code above compiles and works fine, but there are a couple of things we can do to clean the code up a bit. The main thing is that we don’t have to explicitly declare the type of our connection object. Let’s get rid of that declaration and tidy things up.
Look how clean that is!
Just to make sure you understand how to make use of this technique, here’s a more concrete example of using the connection:
Again, you’ll probably want to look at my last post on Using IDisposable objects responsibly to get a better understanding of why we want to use this technique in the first place.
I’ve been on a mission lately to eliminate duplicate code, so there’s a good chance my next two or three posts will be on the same subject.