Saturday, March 15, 2008

C# Extension Methods - Syntactic Sugar That Won't Rot Your Teeth

C# 3.5 introduced extension methods to the language. These are non-member methods that are callable with member method syntax. For example, if we have a class:

class Foo { /**/ }


we can declare an extension method for it like this:
  static class Bar
{
public static void Baz(this Foo f) { /**/ }
}
(The this keyword in the declaration is what marks it as an extension method.) The syntactic sugar is that you are allowed to call Baz on an instance of Foo like this:

new Foo().Baz();

The compiler rewrites the above call to the more traditional:

Bar.Baz(new Foo());

Now that the mechanics are out of the way, let's look at what they are good for. The main benefit of extension methods, in my mind, is that they remove the syntactic penalty of non-member functions. Take Scott Myers's advice [ddj] for C++ class design: "Prefer non-member non-friend functions to member functions." There is little argument that it's a good idea in principle, but there are certainly mixed feelings about the syntactic trade-off [Google seems to bork that thread - the discussion tree it renders doesn't make much sense]. As an example of where you might do this, consider how String.StartsWith() might have been implemented:

public class MyString
{
private Char[] m_chars;
public Char this[int i]
{
get { return m_chars[i]; }
}

public MyString(String s)
{
m_chars = s.ToCharArray();
}

public int Length { get { return m_chars.Length; } }
}

public static class MyStringExt
{
public static bool StartsWith(this MyString str, MyString find)
{
if (str.Length < find.Length) return false;

for (int i = 0; i < find.Length; ++i)
{

if (str[i] != find[i])
return false;
}
return true;
}
}

The same functionality, but with improved encapsulation! There is a downside, of course. Object methods are much more "discoverable" than static functions that happen to accept particular parameters. Member functions have to be declared along with the rest of the class, so there is just one place to look for them [partial classes complicate this a bit]. Microsoft's answer to this is improved Intellisense; extension methods are included alongside regular methods. As long as you're using their IDE, I think it makes up for it.

No comments: