Many developers find that keeping up with new technologies can be challenging and a drain to limited resources. Sometimes a review of basic .NET and C# skills is useful. This review of extension methods addresses the basic concept and implementation. Thousands of implementations are most certainly found in the industry, but in this article I want to address a few popular and useful ones.

Extension methods represent a simple method to incorporate features and functions into basic C# types without complexities or code rewrite. Through extension methods, the developer “adds” methods to existing types without creating new derived classes. The original base class remains intact, but new methods are now merged with the base class.

Extension Methods Explained

Extensions methods are easily designed once the syntax is understood. Generally, the syntax must be public, static, return a typed value, and be attached to an explicit type:

public static string MyNewMethod(this int inValue)

Extensions should be grouped into explicit extension classes / explicit files. Although they may be part of the same namespace, as the primary project, they will serve multiple projects when separated into a shared library. When used in this manner, declare the extension class as public and static:

public static class Extensions
{
   …
}

Implementing a String Extension

IsNullOrEmpty Possibly the most common extension provides a more readable test for null or empty string status. Obviously, the following code snippet works:

if (string.IsNullOrEmpty(myVariable))
{
   …
}

But the IsNullOrEmpty string extension is referenced in a more intuitive manner:

if (myVariable.IsNullOrEmpty())
{
   …
}

Implementing this single extension in a standalone extension class produces:

namespace ExtensionEmbeddedApplication
{
  public static class StringExtensions
  {
    public static bool IsNullOrEmpty
           (this string content)
    {
      return string.IsNullOrEmpty(content);
    }
  }
}

ToTitleCase Sometime uppercase and lowercase is not enough - conversion of the string into proper names is required. In this case, "mark reynolds".ToTitleCase() should produce first-letter capitalization:

public static string ToTitleCase(this string mText)
{
   if (string.IsNullOrEmpty(mText)) return mText;
    
   System.Globalization.CultureInfo cultureInfo =
     System.Threading.Thread.CurrentThread.
     CurrentCulture;
   System.Globalization.TextInfo textInfo =
     cultureInfo.TextInfo;
    
   return textInfo.ToTitleCase(mText.ToLower());
}

RegEx String Extensions

Regular Expressions (RegEx) are difficult to construct and require adjustment from time to time. However, a few simple string extensions permit code that is more readable and more easily maintained.

IsValidEmail One of the most common string checks in today’s Internet-enabled applications is validating email. You can improve readability in programs when you properly use extension methods.

const string EmailRegEx =
      @"\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*";
public static bool IsValidEmail(this string content)
{
   if (string.IsNullOrEmpty(content)) return false;
   return Regex.IsMatch(content, EmailRegEx);
}

IsMatch When a generic RegEx validator is required, an IsMatch extension could be used with an extra parameter:

public static bool IsMatch(this string content,
                           string regEx)
{
   if (string.IsNullOrEmpty(content)) return false;
   return Regex.IsMatch(content, regEx);
}

When called from the main application, the syntax is:

if (myVariable.IsMatch(<My_Test_Expression>))

What Is a Good Extension Method?

Extension methods can be overused and actually begin to convolute the code, thereby negating the advantages. James Michael Hare’s blog suggests a good extension method should:

  • Apply to any possible instance of the type it extends.
  • Apply to the most specific type or interface applicable.
  • Simplify logic and improve readability/maintainability.
  • Be isolated in a namespace so that it does not pollute IntelliSense.

(See more at http://geekswithblogs.net/BlackRabbitCoder.)

The two points may be obscure at first. But creating an extension defined as (this object content) requires that the extension fit every type or class derived from object - all types and classes.

One ingenuous solution to a generic extension solving IsBetween makes use of where T : IComparable condition and, thus, provides assurance of which type receives the extension.

public static bool IsBetween<T>
   (this T actual, T lower, T upper)
   where T : IComparable<T>
{
   return
   (actual.CompareTo(lower) >= 0) &&
   (actual.CompareTo(upper) < 0);
}

IntelliSense

However, many developers may disagree with Mr. Hare’s opinion about polluting IntelliSense; perhaps the desire may be to add extensions and integrate with IntelliSense.

Consider adding IntelliSense to the previous example:

/// <summary>Tests whether value is bounded</summary>
/// <typeparam name="T">Any IComparable</typeparam>
/// <param name="lower">lower bound test</param>
/// <param name="upper">upper bound test</param>
/// <returns>A bool</returns>
public static bool IsBetween<T>

You can find a complete set of recommended tags used in documentation at: http://msdn.microsoft.com/en-us/library/5ast78ax.aspx.

Extension Properties

Sorry, extension properties do not exist. But Eric Lippert offers explanation and rationale in his blog “Why no Extension Properties” (http://blogs.msdn.com/b/ericlippert).

XML Extensions

Two interesting XML extensions found in several forms on the Web are XmlSerialize and XmlDeserialize. (Several other variations are available which address JSON and other serialization approaches.)

IEnumerables and Action

Adding a ForEach action method is one of the coolest extensions made available, thanks to LINQ. Consider this one-line replacement for a full ForEach construct:

var sb = new List<string>() {
   "Fred Flinstone",
   "Barney Rubble" };
    
sb.ForEach(st => Console.WriteLine(st));

This lamda action extension is facilitated with an equally short extension method:

public static void ForEach<T>
   (this IEnumerable<T> @enum, Action<T> mapFunction)
{
   foreach (var item in @enum) mapFunction(item);
}

Conclusion

Language extensions provide powerful language extensions and are gaining popularity. But they can be misused. Keep them simple, focused, and rock solid. Make code readable, but do not introduce hard-to-trace or understand idiosyncrasies. Be careful to extend only types and classes that may utilize the extension.