I've always been a little dissapointed that these methods aren't part of the IList<T> interface; however, with Extension methods we can rectify this. I defined a new method in a static class as:
public static T Find<T>(this IList<T> col, Predicate<T> match)
{
if (match == null)
{
throw new ArgumentNullException("match");
}
for (int i = 0; i < col.Count; i++)
{
if (match(col[i]))
{
return col[i];
}
}
return default(T);
}
This has been working fine for almost a year now, until today when I got a null Reference exception on the for loop. The interesting thing with Extension methods is they are nothing more then a static method that the compiler does some magic with.
To prove this go ahead and create a simple console application. Add an extension method on your favorite type (I choose a string), and call this from your main method. Here's what I used:
static class Extensions
{
public static void ToMe(this string value)
{
if (value == null)
{
Console.WriteLine("Null value");
}
}
}
static void Main(string[] args)
{
string s = null;
s.ToMe();
Console.ReadLine();
}
After you compile this go ahead and fire up reflector or Ildasm and have a look at the IL. In my case I had the following instruction:
call void ConsoleApplication4.Extensions::ToMe(string)
Since all we are doing is calling a static method and passing in a reference to the variable which the extension method was called off of, it becomes perfectly legal to call extension methods on a null reference.
Now in my opinion this is wrong, and a side effect of the implementation, and we should not rely upon this behavior. The correct code should look like:
public static T Find<T>(this IList<T> col, Predicate<T> match)
{
if (match == null)
{
throw new ArgumentNullException("match");
}
if (col == null)
{
throw new NullReferenceException();
}
for (int i = 0; i < col.Count; i++)
{
if (match(col[i]))
{
return col[i];
}
}
return default(T);
}
No comments:
Post a Comment