There’s a very powerful feature in .Net 3.5 called extension methods. In an earlier blog, I used an extension method in my LINQ to XML to format the date retrieved from an RSS feed. If you’re new to the 3.5 framework, you may be wondering what the big deal is.
As a consultant, I have to look at a lot of old and 3rd party code. There are times when I don’t have access to the source code, and I need to add some additional functionality to a class. If I can inherit from the base class, I can just inherit the class and extend it. But what do I do if the class is sealed? Prior to .et 3.5, my options were limited and certainly not as object oriented. I’d have to write some type of wrapper of common function to create the functionality.
As an example, let’s say I wanted to extend string with some additional functionality, such as adding in functionality to reverse a string easily. I create my new class, and try to inherit from the String class, but I get a compilation error. Let’s look at the definition of the String class in .Net:
[SerializableAttribute]
[ComVisibleAttribute(true)]
public sealed class String : IComparable,
ICloneable, IConvertible, IComparable<string>, IEnumerable<char>,
IEnumerable, IEquatable<string>
Because the class is sealed, I can’t inherit from it. Prior to .Net 3.5, I am going to have to create a function and pass in the string. By using extension methods, I am no longer restricted by the “sealed” keywords.
/// <summary>
/// Reverses the specified string.
/// </summary>
/// <param name="s">The string to reverse.</param>
/// <returns>Reversed string</returns>
public static string Reverse(this string s)
{
char[] arr = s.ToCharArray();
Array.Reverse(arr);
return new string(arr);
}
The code above extends any string with a new Reverse function, which reverses the referenced string. Here’s how it is used:
string testString = "MyString";
string reversedString = testString.Reverse();
The new reverse function shows up in Intellisense for any string, which helps speed up coding as well.
So how did this work? It’s all in the definition. First, the class and the function has to be defined as static. Second, the first parameter must begin with this and is a reference to the type this method extends.
There are some restrictions to static methods. For example, the extension method can only access public methods of the referenced class.
Below are some more examples of extending the string class with some additional functionality. A couple of days ago, I posted some examples of getting values from a DataRow safely. This would be another great refactor opportunity to extend the DataRow class to provide this functionality right from the DataRow itself.
using System;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Threading;
namespace Rubicon.Common
{
public static class StringExtensions
{
/// <summary>
/// Reverses the specified string.
/// </summary>
/// <param name="s">The string to reverse.</param>
/// <returns>Reversed string</returns>
public static string Reverse(this string s)
{
char[] arr = s.ToCharArray();
Array.Reverse(arr);
return new string(arr);
}
/// <summary>
/// Converts the string to title case.
/// </summary>
/// <param name="s">The string to convert.</param>
/// <returns>A title case string.</returns>
public static string ToTitleCase(this string s)
{
CultureInfo ci = Thread.CurrentThread.CurrentCulture;
TextInfo ti = ci.TextInfo;
return ti.ToTitleCase(s);
}
/// <summary>
/// Returns true if string is over the specified max length
/// </summary>
/// <param name="s">The string to check.</param>
/// <param name="maxLength">max length.</param>
/// <returns></returns>
public static bool OverMaxLength(this string s, int maxLength)
{
return (s.Length <= maxLength);
}
/// <summary>
/// Returns true if string is under the specified min length
/// </summary>
/// <param name="s">The string to check.</param>
/// <param name="minLength">min length</param>
/// <returns></returns>
public static bool UnderMinLength(this string s, int minLength)
{
return (s.Length <= minLength);
}
/// <summary>
/// Checks the length of the string to make sure it is within the set bounds.
/// </summary>
/// <param name="s">The string to check.</param>
/// <param name="minLength">min length</param>
/// <param name="maxLength">max length</param>
/// <returns></returns>
public static bool WithinValidLength(this string s, int minLength, int maxLength)
{
return ((s.Length >= minLength) && (s.Length <= maxLength));
}
/// <summary>
/// Determines whether the string is alpahbetic only.
/// </summary>
/// <param name="s">The string to check.</param>
/// <returns>
/// <c>true</c> if [is alpha only] [the specified s]; otherwise, <c>false</c>.
/// </returns>
public static bool IsAlphaOnly(this string s)
{
Regex regPattern = new Regex("[^a-zA-Z]");
return !regPattern.IsMatch(s);
}
/// <summary>
/// Determines whether the string is alphanumeric.
/// </summary>
/// <param name="s">The string to check.</param>
/// <returns>
/// <c>true</c> if [is alpha numeric] [the specified s]; otherwise, <c>false</c>.
/// </returns>
public static bool IsAlphaNumeric(this string s)
{
Regex regPattern = new Regex("[^a-zA-Z0-9]");
return !regPattern.IsMatch(s);
}
}
}
Extension methods are a very powerful tool, and enhance OOP concepts like encapsulation. They will help you organize your code, and extend the functionality of classes previously you could not modify. I obtained my first taste of Extension Methods in this book as I was learning LINQ, and I highly recommend it.