A reader added the following comment to my
Neat Tricks With Extension Methods article:
Is it possible to make something like :
namespace System
{
public static class SystemExtensions<T>
where T
: Something
{
public static bool IsNullOrEmpty(this
T obj)
{
return (obj ==
null || obj.Length == 0);
}
}
}
Unfortunately, the answer is, no, you can't quite do that. There are two problems
here: 1) it's useless to add a generic parameter to a static class because it can
never be instantiated (since it's static) and 2) the generic constraint language
isn't rich enough to ensure that methods or properties are available on a generic
argument unless they already exist in an implemented interface. The solution to
the first problem is to make the method generic and not the class. However, the
second problem makes this impossible since String and Array don't implement an interface
that exposes the Length property. If they did, we could write something like this:
namespace System
{
public static class
SystemExtensions
{
public static bool IsNullOrEmpty(this
IHasLength obj)
{
return (obj ==
null || obj.Length == 0);
}
}
}
While the reader's request isn't really possible, it did lead me to realize a
limitation of the Array.IsNullOrEmpty method that I presented in the previous
article. Originally, I had written an extension method called IsNullOrEmpty
that worked with arrays. However, it makes sense to broaden the use of this extension
method by making it target ICollection like this:
using System.Collections;
namespace System
{
public static class SystemExtensions
{
public static bool IsNullOrEmpty(this
ICollection obj)
{
return (obj ==
null || obj.Count == 0);
}
}
}
Written that way, our extension method not only works with arrays, but any .NET
collection as well!
using System;
using System.Collections;
using System.Collections.Generic;
namespace ExtensionMethodTests
{
static class Program
{
public static bool IsNullOrEmpty(this
ICollection c)
{
return (c == null || c.Count == 0);
}
static void Main(string[] args)
{
string[] nullArray = null;
string[] emptyArray = { };
string[] realArray = { "Dustin",
"Dustin's Trophy Wife" };
Console.WriteLine("nullArray.IsNullOrEmpty: {0}", nullArray.IsNullOrEmpty());
Console.WriteLine("emptyArray.IsNullOrEmpty: {0}", emptyArray.IsNullOrEmpty());
Console.WriteLine("realArray.IsNullOrEmpty: {0}", realArray.IsNullOrEmpty());
Console.WriteLine();
Stack nullStack =
null;
Stack emptyStack =
new Stack();
Stack realStack =
new Stack(new string[] {
"Dustin", "Dustin's Trophy Wife" });
Console.WriteLine("nullStack.IsNullOrEmpty: {0}", nullStack.IsNullOrEmpty());
Console.WriteLine("emptyStack.IsNullOrEmpty: {0}", emptyStack.IsNullOrEmpty());
Console.WriteLine("realStack.IsNullOrEmpty:
{0}", realStack.IsNullOrEmpty());
Console.WriteLine();
List<string> nullList =
null;
List<string> emptyList =
new List<string>();
List<string> realList =
new List<string>(new string[] {
"Dustin", "Dustin's Trophy Wife"
});
Console.WriteLine("nullList.IsNullOrEmpty: {0}", nullList.IsNullOrEmpty());
Console.WriteLine("emptyList.IsNullOrEmpty: {0}", emptyList.IsNullOrEmpty());
Console.WriteLine("realList.IsNullOrEmpty: {0}", realList.IsNullOrEmpty());
}
}
}
Happy spelunking!