Using C# Delegates to Translate Text Into Geek Speak!
Much like my article on using extension methods, I want to talk about another cool feature of C# known as delegates, but to make it more useful, I want there to be a purpose to it. Let’s get ready, let’s get ready, let’s get ready to Geek Speak!
Years ago I remember we used to play around with these UNIX utilities that would take as input a text stream and then translate it into other languages. I don’t mean anything serious like French or German but instead into Shakespearean or “Redneck“.
For example, running this:
echo "hello, how are you?" | cockney |
might produce something like:
'Allo, right, how are yer? |
in a cockney translator. All very useful!
Let’s Talk Geek
Let’s think about how we might achieve something like that, but for Geek Speak. If you don’t already know, Geek Speak is (partly) where some letters are replaced with numbers. In my version, I also want it to be in lower case, based on this mapping:
a -> 4 |
Here’s an example:
hello, simon, how are you? -> h3ll0 5im0n h0w 4r3 y0u? |
There are lots of other translations of characters that could be made, but that’s enough Geek for now!
Doing It The Inflexible Way
If we wanted to write a program that did this, we might come up with something like this:
1 | class Program |
We simply create an object of type err…SimpleTranslator
and then invoke the DoTranslation
method to return the newly created string. In fact, given that the function requires no state, a static function would be even better. However, what if we wanted to translate the text into another language such as Uppity (a little known language were all the characters are in uppercase)? We could add a new method like this:
1 | class SimpleTranslator |
Or what about keeping the same method, but adding a selection statement?
1 | class SimpleTranslator |
Erm…let’s just ignore the method we use to choose which language here - using a string is just for illustrative purposes and fairly shocking! Please?! The point is, it doesn’t look too good.
Also, it isn’t all that flexible. What if we wanted to use a different class or other methods to translate? Right now, we can’t because we’re tied to SimpleTranslator
.
Another point worth mentioning is that we are baking all this logic inside the translator. It would be so much better if we could extract that and put the onus on the user of the class to provide their own translation function. In a sense, this is inversion of control. All in all, not particularly desirable.
Starting To Delegate
Of course, there is a better way and that is by using delegates. So what are they?
A delegate is a type that represents references to methods with a particular parameter list and return type. When you instantiate a delegate, you can associate its instance with any method with a compatible signature and return type. You can invoke (or call) the method through the delegate instance. – https://msdn.microsoft.com/en-us/library/ms173171.aspx
Or, put another way, they are a bit like C’s pointers to functions. In the language C, it is possible to create a variable which can point to memory or, as in this case, a block of code which you can then execute. C is good like that, but very dangerous, naturally!
C# however is much more careful thanks to type safety and checking, which will ensure that you can only point to valid (read: safe) things.
In our case, we’re going to create a delegate and assign a function to it which will do all the hard work of translating our text. As far as the translating class is concerned, it doesn’t care, so long as it points to a valid method. This is best shown with an example:
1 | class Program |
Let’s break this down a little.
On line 14 we are declaring the delegate and basically saying that our new type is to be called TranslatorFunctionType
and that it is allowed to point to functions that take one parameter (a string) and will return a string. What can make this seem difficult to read is that it also looks just like a method signature. Tricky!
Line 18 is just an auto-property that allows us to assign the method to the delegate variable. It didn’t need to be done this way, but I think it’s nicer. Another option would be something like this:
1 | public TranslatorFunctionType TranslatorFunction; |
We would need to expose the field publicly and assign the function with something like:
1 | var t = new Translator(); |
Line 22 is where the magic happens. Once the delegate field has been assigned, we can use it just like a method and call it. Super-cool!
Lastly, line 9 is where we actually assign the method to the delegate. In this case, we use a method inside the class GeekTranslator
. It didn’t need to be in a class - I just chose that for this example.
Before we continue, we can take a quick look at what the output looks like. Pictures do make the world a better place!
Another nice feature of delegates is that we don’t actually have to use the new keyword when assigning to the delegate. C# is clever enough to understand this:
1 | t.TranslatorFunction = gt.Translate; |
Adding Another Translator
Now, this is so much easier. Let’s add our Uppity translator.
1 | class UppityTranslator |
And we can call it using this easy change:
1 | class Program |
Note the differences on the highlighted lines.
Chaining Delegates With += and -=
You might also create a chain of delegates that can all be called with one method invocation. Here’s how it would look to make this easier to visualise:
1 | t.TranslatorFunction = geek.Translate; |
In our case, this won’t work and only the last translator will function (try it and see), but in other situations, you can imagine methods with a void signature doing all kinds of interesting things.
Using Anonymous Delegates
You don’t have to use fully labelled methods though. A handy thing is that we are able to use anonymous methods when assigning to the delegate which is a nice alternative if you don’t want the overhead. Here’s one way you could achieve that for the Geek translator:
1 | t.TranslatorFunction = delegate(string input) |
Summary
Delegates are pretty amazing, really! I have only scratched the surface of what you can do with them, but hopefully it gives you a taste and encourages you to learn a bit more and use them in your projects. H0p3 y0u 3nj0y3d it!
Hi! Did you find this useful or interesting? I have an email list coming soon, but in the meantime, if you ready anything you fancy chatting about, I would love to hear from you. You can contact me here or at stephen ‘at’ logicalmoon.com