Today, we are going to take a look extension methods, which is a
language feature introduced to C# in .NET 3.0. Extension methods are a
piece of syntactic sugar that allow you add new functionality to a class
that you don't have direct access to. Sound cool yeah? Cause it is.
With C# before extension methods, it was common to have classes full of
utility methods that mostly just augmented the functionally of some part
of the .NET framework. Say, for instance, there were some other things
that you thought would be handy to be able to do with strings whenever
you wanted - perhaps you were needing to reverse the words in a string
relatively often. You would probably write a class like this:
public static class StringUtils
{
public static string ReverseWords(string str, char sep)
{
char temp;
int left = 0, middle = 0;
char[] chars = str.ToCharArray();
Array.Reverse(chars);
for (int i = 0; i <= chars.Length; i++)
{
if (i != chars.Length && chars[i] != sep)
continue;
if (left == i || left + 1 == i)
{
left = i + 1;
continue;
}
middle = (i - left - 1) / 2 + left;
for (int j = i - 1; j > middle; j--, left++)
{
temp = chars[left];
chars[left] = chars[j];
chars[j] = temp;
}
left = i + 1;
}
return new String(chars);
}
public static string ReverseWords(string str)
{ return ReverseWords(str, ' '); }
}
And then, when you wanted to reverse the words in a string, you would
call it like this:
string myString = "I Am A String";
string backwards = StringUtils.ReverseWords(myString);
This isn't a bad technique, and it works well as long as you are the
only one working in this code base. But say someone else comes along and
also needs to reverse the words in a string. If you never told them
about your
StringUtils
class, they might go off and write their own
implementation - and now you end up with two implementations of the same
thing in your codebase. Very sad.
It is to fix this problem, and to make your code read a little bit
nicer, that extension methods come in. Wouldn't it be handy if you could
make
ReverseWords
just another method that hangs off of the string
class? No more having to know where all the utility methods are - they
would be hanging right off the class that they operate on! If you've
been using .NET 3.5 at all, you have probably been using extension
methods and not even knowing it. When you include the namespace
System.Linq
in your file (which .NET 3.5 does by default) you get
about 3 dozen methods added onto the IEnumerable\ interface. You can
tell that a method is an extension method because Visual Studio
intellisense will show them like this:
All the extension methods have that little blue down arrow as part of
their icon, and the tooltip will have the word "(extension)" in front of
the method name.
So now we want to make this
ReverseWords
function an extension method.
It is actually only a single change. You want to change the method
signature from what it currently is:public static string ReverseWords(string str, char sep)
to this:
public static string ReverseWords(this string str, char sep)
That's right, all you have to do is add '
this
' before the first
argument. Now it is an extension method on whatever the type of the
first argument is. So here is all of the new StringUtils
code:public static class StringUtils
{
public static string ReverseWords(this string str, char sep)
{
char temp;
int left = 0, middle = 0;
char[] chars = str.ToCharArray();
Array.Reverse(chars);
for (int i = 0; i <= chars.Length; i++)
{
if (i != chars.Length && chars[i] != sep)
continue;
if (left == i || left + 1 == i)
{
left = i + 1;
continue;
}
middle = (i - left - 1) / 2 + left;
for (int j = i - 1; j > middle; j--, left++)
{
temp = chars[left];
chars[left] = chars[j];
chars[j] = temp;
}
left = i + 1;
}
return new String(chars);
}
public static string ReverseWords(this string str)
{ return str.ReverseWords(' '); }
}
Now, you can do things like:
string myString = "I Am A String";
string backwards = myString.ReverseWords();
And it even shows up in intellisense:
Ok, now for some limitations of extension methods. You don't get access
to any of the actual innards of the class that you are writing the
extension method for, so no access to any private or protected members.
The extension methods must be declared inside of a static class, and
they must be declared as static methods. In fact, you actually can still
call the extension method directly - for instance:
string myString = "I Am A String";
string backwards = StringUtils.ReverseWords(myString);
That code will still work, even after
ReverseWords
was made an
extension method. This makes a lot of sense in terms of backwards
compatibility for people who had huge files of utility functions. Another limitation is that you can't override an existing method with an
extension method. If the method already exists on the class, the
extension method just won't get called. The code will compile just fine,
but it will always use the method that exists in the class. For
instance:public static Test
{
public static string ToString(this int val)
{ return "Ha Ha"; }
}
int foo = 5;
Console.WriteLine(foo.ToString());
This will print out '5', and not 'Ha Ha' - and this is very good,
otherwise people could be in for a world of confusion.
I mentioned a little bit earlier that using the 'Linq' namespace adds a
whole bunch of methods to
IEnumerable<T>
. You might have wondered "But
that is an interface! You can't add methods with implementations to
interfaces!" Well guess what - this is yet another handy feature of
extension methods. You can add extension methods to interfaces, and
every class that ever implements that interface suddenly has your new
method. Very handy!
Well, that is it for my rambling on about extension methods for today.
Source Files:
Source Files:
Comments
Post a Comment