There are a few instances where I see extension methods being valuable and saving you from excess typing. The biggest one would be a set of extensions that bring all of the lovely members of List to their respective IEnumerable/ICollection/IList brethren. Along the lines of:
public static void AddRange<T>(this ICollection<T> col, IEnumerable<T> collection)
public static ReadOnlyCollection<T> AsReadOnly<T>(this ICollection<T> col)
public static ICollection<T> ConvertAll<T, TOutput>(this IEnumerable<T> col, Converter<T, TOutput> converter) etc...
Any other use of extension methods will force me to stab you in the eye and cut off your right pinky finger, making it impossible for you to type the semi-colon (;) character and relegating you to the ranks of VB.Net programmers the resulting humiliation of which should cause you to finish the job yourself.
Let me summarize the short comings of extension methods and pick on the MvcToolkit as an abusing offender. Read more bloggers (Derik, John, and Karl) who agree with me in spirit if not in eye-stabbing, pinky severing practice.
Extension Methods...
- Should be used sparingly. (Wear goggles and a gauntlet while you make your case to me, just to be safe)
- Are nothing more than a compiler trick.
- Are achievable through more discoverable means.
- Are NOT mixins.
- Are not overrideable.
- Are not discoverable at run-time.
- Will cause you pain.
- Should absolutely NOT be used to add methods to classes for which you own the source code.
Consider the following code which compiles:
namespace Pain
{
using ExtensionMethods.AreThe;
public enum Eye { Left, Right }
public class ExtensionMethodUserPunisher
{
public void StabEye()
{
this.StabEye(Eye.Left);
}
public void SeverPinky()
{
}
}
}
namespace ExtensionMethods.AreThe
{
using Pain;
public static class Extensions
{
public static void StabEye(this ExtensionMethodUserPunisher subject, Eye eye)
{
}
}
}
Now consider this almost identical code, which does not compile:
namespace Pain
{
using ExtensionMethods.AreThe;
public enum Eye { Left, Right }
public class ExtensionMethodUserPunisher
{
public void StabEye()
{
StabEye(Eye.Left);
}
public void SeverPinky()
{
}
}
}
namespace ExtensionMethods.AreThe
{
using Pain;
public static class Extensions
{
public static void StabEye(this ExtensionMethodUserPunisher subject, Eye eye)
{
}
}
}
Now consider what happens if you modify your using statement:
namespace Pain
{
using ExtensionMethods.AreThe.Devil;
public enum Eye { Left, Right }
public class ExtensionMethodUserPunisher
{
public void StabEye()
{
this.StabEye(Eye.Left);
}
public void SeverPinky()
{
}
}
}
namespace ExtensionMethods.AreThe
{
using Pain;
public static class Extensions
{
public static void StabEye(this ExtensionMethodUserPunisher subject, Eye eye)
{
}
}
}
namespace ExtensionMethods.AreThe.Devil
{
using Pain;
public static class Extensions
{
public static void StabEye(this ExtensionMethodUserPunisher subject, Eye eye)
{
subject.SeverPinky();
}
}
}
You code still compiles just fine, but you will get different behavior and it should be fun tracking down why.
Oh but you can abuse any language feature, and you would never do something like this, and this is never going to happen to you, and you are going to extend the crap out of System.Object because you can. Fine, but when the time comes I'm not even going sully my pen with your ocular juices.
Back to the MvcToolkit. Rob's eye get a grace period, because this is only a CTP. I'm not privy to the internal workings of the MVC team so I'm not sure why this was initially developed as a separate assembly. I know that the plan is to move it into System.Web.Extensions. I hope that when it is moved that all of the 75+ HtmlHelper extension methods become first class members. Here's why: Not all consumers of HtmlHelper are compiled, making extension methods pretty useless. And maybe I want to override the output of TextBox without re-writing the whole method and without resorting to the mess demonstrated above.
Please feel free to flame me with your comments exhorting the virtues of extension methods.
posted @ Friday, January 04, 2008 12:41 PM