Introduction
A couple of weeks ago, I finally managed to get a copy of Visual Studio 2008. Toying around with the new features of C# 3.0, I discovered some interesting tricks using extensions. Extensions are static functions introduced in C# 3.0. They allow developers to extend existing types without having to change the original code.
Example
Creating a new extension is relatively simple. Define a static
function in a static
class and pass the type you want to extend as a parameter. It must be the first parameter and has to be marked with the keyword this
. Additional parameters are also possible.
namespace App.Utility
{
public static class Extensions
{
public static string AddExclamationMark(this string text)
{
return text + "!";
}
public static string AddAditionalText(this string text, string add)
{
return text + add;
}
}
}
The class name you choose is irrelevant since the functions can now be called by the defined type. Visual Studio 2008 also supports them in IntelliSense. The best way to use extensions is to collect them all in a static utility class. If you plan on using extensions a lot, you might want to split them in different classes and namespaces.
"Hello World".AddExclamationMark();
Unluckily, extensions cannot be defined as properties. You also can't override existing methods.
String validation C# 1.0 to 3.0
Validating strings is a common task, especially checking if they aren't null
or empty. Extending strings with custom functions can make life a lot easier. Let's look first at the possible implementations in C# 1.0 and 2.0:
string input = "Lorem ipsum";
if(input != null && input != "")
{
}
if(input != null && input.Trim() != string.Empty)
{
}
if(!string.IsNullOrEmpty(input))
{
}
I often use IsNullOrEmpty
, but I don't actually like it much. First of all, I usually want to know if the string has a value, not the other way round. Secondly, this function also accepts strings consisting only of empty spaces, and I can't use Trim
since the string might be null
. To solve this in C# 2.0, I would have to create a static utility method:
namespace App.Utility
{
public static class StringHelper
{
public static bool HasValue(string s)
{
return s != null && s.Trim() != string.Empty;
}
}
}
if(Utility.StringHelper.HasValue(input))
{
}
The resulting code is cumbersome, ugly, and easily forgotten. Included in a common framework, chances are high that other developers in your team won't find it, let alone use it.
Enter Extension Functions
The only thing we have to do now is add the keyword this
before the first parameter:
public static bool HasValue(this string s)
{
return s != null && s.Trim() != string.Empty;
}
HasValue
is then available on all strings. As it is now listed in the IntelliSense box, it is also likely that the rest of your team will actually use the function.
using App.Utility;
if(input.HasValue())
{
}
Now to the interesting part. As we all know, calling functions on an uninitialized object results in an exception. This isn't automatically true for extensions.
bool b;
b = "Lorem ipsum".HasValue();
b = "".HasValue();
string s = null;
b = s.HasValue();
How come this works? Well, extensions only look like normal function calls. They are actually still static functions of the static class (in this case, StringHelper
). So, the code is identical to this:
if(StingHelper.HasValue(input))
{
}
Jumping the sharp
I found calling functions on non-initialized objects quite intriguing. Couldn't this always be used instead of verifying that an object isn't null
? The following examples shouldn't be used in production code (well, except if you really want to).
Let's assume we have a database filled with personal information. Each entry is represented by the class Person
. Every person should have a birth year, but our data is rather faulty.
using System;
using System.Collection.Generics;
public class Person
{
private string name;
private int birthYear;
public string Name
{
get { return name; }
set { name = value; }
}
public int BirthYear
{
get { return birthYear; }
set { birthYear = value; }
}
}
public class Programm
{
public static void Main()
{
List<person> personList = new List<person>();
personList.Add(new Person(){ Name = "John", BirthYear = 1980 });
personList.Add(new Person(){ Name = "Jane", BirthYear = 1987 });
personList.Add(new Person());
personList.Add(null);
personList.Add(new Person(){ Name = "Bob", BirthYear = 0 });
foreach(Person person in personList)
{
if(person != null)
{
if(person.BirthYear > 0)
{
Console.WriteLine(person.BirthYear);
}
}
}
}
}
We have to check that each Person
isn't null
before we access the BirthYear
property. With Extensions, we don't have to. Instead, we return a default value.
public static class PersonExtension
{
public static int GetBirthYear(this Person person)
{
if(person != null)
{
return person.BirthYear;
}
return 0;
}
}
foreach(Person person in personList)
{
if(person.GetBirthYear() > 0)
{
Console.WriteLine(person.BirthYear);
}
}
I don't think it is a good idea to start writing extensions for every single property though!
History
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.