Creating an Extension Method in C# - ROT 13

I was listening to a podcast today featuring Troy Hunt on Dot Net Rocks where he talked about how he had once written a question on Stack Overflow about what people thought made a good password encryption method. One of the ideas he received was, unbelievably, to use ROT-13 on the pass phrase.

I also watched another great video on Pluralsight by Deborah Kurata (called Object Oriented Programming in C#) in which, briefly, she talked about using extension methods.

You guessed it. The stars aligned and I suddenly realised that what the world needed was a quick tutorial on how to combine the two!

What is ROT 13?

Before we take another step, we’d better make sure you understand what is meant by ROT-13.

ROT13 is a shortened form for “rotate by 13” and in simple terms, means that for each alphabetic character in a text string, you replace it by the letter 13 places further along in the alphabet from it. Should you pass the letter ‘Z’, you go back to ‘A’. That means all letter ‘A’s become ‘M’s and all ‘M’s become ‘A’s.

Still not clear? Let’s take a small example. If I wanted to use this on the word “HELLO”, this is what I would end up with: HELLO -> URYYB Count along on your fingers from ‘H’ 13 places and you will get the letter ‘U’. ‘E’ becomes ‘R’, the two ‘L’s are made into ‘Y’ and because ‘O’ plus 13 characters goes past the letter ‘Z’, it wraps back around to ‘B’.

For a small splash of history, you might be interested to know that it is also known as a Caesar Cipher because he actually used it for his personal correspondence. There you go!

Even today, it is popular on bulletin boards to hide spoilers or another place you can see it used is on the Geocaching website (geocaching.com) where it hides the hints about where to find caches. Note: It should not be used to encrypt passwords, of course!

What Exactly Are Extension Methods?

An extension method in C# is a way to add functionality to existing classes without rewriting the class or recompiling it. Why is that quite cool? Well, let’s think about what we would need to do to create this kind of function using other methods. One way we could do it would be to create a helper class and add it as a member function. It might look like this:

1
2
3
4
5
6
7
public class Helper
{
public string ROT(string input)
{
//...
}
}

That’s a bit pointless though because we don’t need any state to be maintained in the helper and means that we would need an instance object, each time. Instead, why not try creating a static class like so:

1
2
3
4
5
6
7
public static class Helper
{
public static string ROT(string input)
{
//...
}
}

That’s an improvement because now we can do things like: Helper.Rot13(...). But, wouldn’t it be so much nicer if we could add a member function to the String class because:

  • This is a string based operation that fits nicely with some of the others and,
  • It just looks so much neater.

Well, we can!

How Do We Create An Extension Method?

Actually, in the static class example above, we were really close to finishing the extension method. There is one last thing you need to do and that is to add the keyword: this to the parameter list:

1
2
3
4
5
6
7
public static class Helper
{
public static string ROT(this string input)
{
//...
}
}

Look closely. Can you see it? That’s it! Really, it is. In this case, we’ve added an extension method to the STRING class, but you can just as easily add one to any other class. Just replace STRING with the class you want to add to (e.g. int, Customer, CheekyLittleClassName; it’s up to you).

Calling The ROT Method

This is how we could use the function:

1
2
String input = "I bet you can't work out what this will become?";
input = input.ROT();

Plus, when we look at intellisense for the string, we have this fantastic addition:

The Implementation

Back to our ROT-13 task. I will show you two ways that you might implement this and then I will discuss the one that I favour and why. Take a quick look at this ASCII chart though because it is integral to understanding how those letters are represented in memory (note: I am ignoring UTF etc. for simplicity).

Method 1: Using Arithmetic

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public static class Rot
{
public static string ROT(this string input, int num)
{
string result = String.Empty;

foreach (var c in input)
{
char nextC = c;

if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <='z'))
{
nextC = (char)((int)nextC + num);
if (c <= 'Z' && nextC > 'Z')
{
nextC = (char)((int)nextC - 'Z' + 'A' - 1);
}
else if (c <= 'z' && nextC > 'z')
{
nextC = (char)((int)nextC - 'z' + 'a' - 1);
}
}

result += nextC;
}
return result;
}
}

Note that I pass in a numeric value. That’s so that we have a bit more flexibility over how much we rotate the characters allowing us to do more than ROT-13. The basic algorithm is:

  • For each character in the input text, check to see if it is alphabetic (upper or lower case).
  • If it is…
    • Add on the amount we want to increment the character by (13 usually, but that is down to the user of the member function)
    • If when we add that amount on, we end up with a letter which is outside of the range A-Z or a-z, alter the resultant value to bring it back into range.

Let’s zoom in on how we bring the values back into range (that is, if the result zipped past the letter Z). I’ll use the uppercase letters for my example:

1
2
3
4
if (c <= 'Z' && nextC > 'Z')
{
nextC = (char)((int)nextC - 'Z' + 'A' - 1);
}

Here, I am asking whether the input was upper case but the result went past the letter ‘Z’. If it did, I take the result, subtract the letter ‘Z’ (as an integer) from it, add the value for ‘A’ back on and then remove 1. That probably made sense to no-one! Let’s use an example. Assume I passed in the letter ‘Z’ (ASCII code 90) and add 13 (for example), I would end up with the letter ‘g’ (ASCII code 103 = 97 + 13). You can see why I included that ASCII chart above in now, can’t you? That’s a clear example of NO rotation! I pick that situation occurring with the nextC > 'Z'. So, next, I subtract the value for ‘Z’, which is 90 (in ASCII), giving me 13 (103 - 90). I then restate that as a letter by adding on the value for ‘A’ (which is 65), giving me 78 (the character for ‘N’). Whoops. We’ve gone a little too far. The final step is to subtract 1, giving us the letter ‘M’ (or 77 in ASCII).

Method 2: Using a Lookup String

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public static class Rot
{
public static string ROT(this string input, int num)
{
string charSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
string result = String.Empty;

foreach (var c in input)
{
char nextC = c;

if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <='z'))
{
nextC = charSet[(charSet.IndexOf(nextC) + num)];
}

result += nextC;
}
return result;
}
}

This method uses a lookup string and relies on the fact that no matter where I start, should I add on 26 (a number I don’t even want to go as high as), I will at most run through all the letters again. By adding in the lowercase letters too, I can handle both sets of letters (upper and lower). To begin, I ask if the character is a letter and if it is, I find it in my lookup string (charSet), add on the amount to increment and use that as my result.

Adding Some Defensive Coding

1
2
3
4
5
6
7
8
if (num < 1 || num > 25)
{
throw new ArgumentOutOfRangeException("Only increments between 1 and 25 (inc) allowed.");
}
if (String.IsNullOrWhiteSpace (input))
{
throw new ArgumentException("Input string must be non-null and contain non-whitespace.");
}

Just for completeness, let’s add some defensive coding in to prevent any undesirable arguments. The value to increment the letters by would be pointless if it were zero (no change) and negative values aren’t in it’s remit. Equally, using 26 would just rotate the character back to it’s original position and anything higher makes no sense. I also wanted to make sure that the input had something at least to work with, but that wouldn’t stop strings like "[193" being passed in. They won’t cause any problems but it would be a little waste of time. One final look at how to use the (new) function, with a numeric argument:

1
2
String input = "Now you can work this out!";
input = input.ROT(13);

My Preference

I prefer the lookup string because it is much easier to understand. I don’t think there is any real performance hit on using it and the extra memory required is negligible. What do you think? Hopefully this has enlightened you about extension methods and if not, well, “V GEVRQ”.


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