Blog Moved to http://podwysocki.codebetter.com/

Blog Moved to http://podwysocki.codebetter.com/
posts - 277 , comments - 156 , trackbacks - 27

Extensions Methods for Good and Evil and Mixins

Lately, I've been evaluation my use of extension methods.  Extension methods have a good use, but that can quickly turn to overuse and confusion. 

The Evil

When I start seeing these methods, I really start to wonder if it's really necessary.  In fact, I run away screaming with my hands flailing above my head.

internal static class ExtensionMethods
{
     public string IsValidEmailAddress(this string email)
     {
          ...
     }

     public DateTime IsBefore(this DateTime date)
     {
          ...
     }
}

For readability sake, it's very tempting to make this for a string that happens to be an email address, but come on!  There's a separation of concerns which quickly approaches this.  Why not make a custom type instead of you're so worried about it being a valid email address.

To me, extension methods should be avoided where ever possible and treated as code smells when they are unavoidable.  Extension methods are great in LINQ, so the smell is definitely tolerable, but I warn against the patchwork extension method frameworks.  But, obviously there are some good uses to them.

The Good

That's on the abuse side, but there are some good examples out there as well.

For example, Greg Young discusses using Extension Methods in the context of using Fluent Fixtures which is a topic near and dear to my heart.  This is just a simple example of what he goes over:

public class TransactionBuilder
{
     private string accountNumber;
     private double balance;

     public TransactionBuilder WithAccountNumber(string accountNumber) { ... }

     public TransactionBuilder Withdrew(double amount) { ... }

     public TransactionBuilder(string accountNumber, double balance) { ... }

     public static implicit operator Transaction(TransactionBuilder builder)
     {
          return new Transaction(accountNumber, balance);
     }
}

And then the extension method goodness comes into play:

public class Builder
{
}

public class Create
{
    public static Builder New = new Builder();
}

public static TransactionBuilder Transaction(this Builder s)
{
    return new TransactionBuilder();
}

So, now I can have a nice fluent statement such as:

Create.New.Transaction().WithAccount("12345").WIthdrew(57);

Now, that is cool!  This allows you to create any number of things from the Create class without much effort whatsoever.  This is perfect for the Fluent Fixtures scenario of building objects.  Great stuff...

Other uses can be found here:

Mixins

But, what about mixins?  Mixins are a wonderful feature of such dynamic languages such as Python, Scala and Ruby.  Just a simple example of a Ruby mixin is below:

class FullName
  attr_accessor :first, :middle, :last   
  def initialize(f, m, l)
    @first, @middle, @last = f, m, l
  end

  def <=>(other)
    [@first, @middle, @last] <=> [other.first, other.middle, other.last]
  end

  # The mixin to get < and <= as well
  include Comparable
end

Can we extend C# 3.0 and beyond to give us the same kind of functionality?  Bill Wagner included a sample on MSDN on how to do so.  This could be a good approach for mocking purposes so that you don't have to rely on static helper classes such as System.IO.File, System.IO.Path and so on.

public interface IPath
{
     FilePath { get; }
}

And then create a mixin such as this:

public static class ExtensionMethods
{
     public static IsFile(this IPath path)
     {
          return File.Exists(path.FilePath);
     }
}

And then when you implement the IPath interface, you get the IsFile method for free...

Will we ever see more native approaches to this in C# 4.0?
kick it on DotNetKicks.com

Print | posted on Friday, January 11, 2008 6:54 PM | Filed Under [ Microsoft C# ]

Feedback

No comments posted yet.
Post A Comment
Title:
Name:
Email:
Comment:
Verification:
 
 

Powered by: