Extension Methods

By Michael Flanakin @ 3:02 PM :: 1949 Views :: .NET, Development :: Digg it!

Karl Seguin Mobile-ready link Syndicated feed talks about extension methods Mobile-ready link, which are part of the next release of both C# and VB; specifically he suggests avoiding them. He quotes the C# documentation by stating...

"Extension methods are less discoverable and more limited in functionality than instance methods. For those reasons, it is recommended that extension methods be used sparingly and only in situations where instance methods are not feasible or possible."

This is pretty much the impression I've had about them since I first saw them. I love the idea of having them, but all it really gives us is a new way to call our existing functionality. When you think about it this way, it seems pretty useless; especially when you consider the fact that it comes with some baggage. I can see developers getting confused when they see an extension method used in one project, but can't seem to find the same method when on a different project. The problem here is that simply looking at a code snippet doesn't clue you in on the fact that a method is an extension method. For this, you'll have to at least hover over the method and gleam that knowledge out of the tooltip or intellisense. Based on this, I'd tend to agree with Karl and say extension methods should be avoided; then again...

Karl claims he can't think of a potential use of extension methods, but I have two that I've thought about a few times. The first, which was the very first thing that hit me after being introduced to extension methods, is extending .NET. If you can't imagine that, let me introduce you to the universal problem that is the string. .NET 2.0 brought us String.IsNullOrEmpty(), but that's not enough. Why not? Because I need something that also checks for whitespace. Essentially, what I'd like is a String.IsBlank() method. Pretty simple, but very useful.

public static class StringUtil
{
    public static bool IsBlank(this string value)
    {
        return (value == null || value.Trim().Length == 0);
    }
}

Which would you rather see: StringUtil.IsBlank(username) or username.IsBlank()? Personally, I like the latter. The alternative is extending the class in question, but for something like String, which is so ubiquitous, that's not a serious option.

Want another example? I'll give you two, both of which relate to domain objects. Domain objects, as opposed to business objects, hold state and only state. You don't see any actionable methods on a good domain object. Typically, these objects are used to pass state between different systems or even throughout a single system. Business logic doesn't need to be everywhere, so a pure, state-based object is often the answer. Of course, some people like methods off of their state-based objects. Extension methods can give us the best of both worlds -- the simplicity of a condensed logical structure and the flexibility of a layered architecture. The first example I'll show is with validation.

public class IForm { ... }
public class BasicForm : IForm { ... }
public class AdvancedForm : IForm { ... }

public static class FormValidator
{
    public static bool IsValid(this BasicForm form) { ... }
    public static bool IsValid(this AdvancedForm form) { ... }
}

As you can probably gather, this will add an IsValid() method to the two concrete IForm implementations. Sure, we could simply call FormValidator.IsValid(), but that's just not as clean. Still not seeing it? Let me add something else to the story...

public static class FormDelegate
{
    public static void Create(IForm form) { ... }
    public static void Update(IForm form) { ... }
    public static void Save(this IForm form)
    {
        if (form.IsNew)
            Create(form);
        else
            Update(form);
    }
}

If you're not seeing the value of separating logic from state, you're just not going to get this at all. I could go into my reasoning behind some of the decisions I made in these implementations, but I'll save those for another day. For now, let me just finish up my code sample with the code you'll actually be using. Oh, and by the way, I prefer create/read/update/delete (CRUD) method names, but "save" comes with a graceful simplicity. I go back and forth, but seeing as tho this is about simplicity, "save" makes more sense.

IForm form = FormFactory.Create(...);
...
if (form.IsValid())
    form.Save();

This pretty much saves you from having to use the more verbose...

if (FormValidator.IsValid(form))
    FormDelegate.Save(form);

And that's it. I love the idea... as if you couldn't tell. I do think the practice should be somewhat limited, however. And I don't know whether or not I'd do this in my projects. I merely thought about the ability to do this when I read Karl's post. I'd be interested in seeing how others might take advantage of the feature.

Ratings