Refactoring a static method (on a generic class) to an extension method‏

The Goal

I needed to perform this refactoring today, and it took me a few mins to figure out how to do this in a safe way using resharper. My goal was to refactor usages like:

Mapper<DestinationType>.Map(Source)

to use an extension method so I can use the syntax similar to:

Source.MapTo<DestinationType>();

which I find to be less verbose, more discoverable, and more readable. This however was slightly more difficult than I hoped; resharper didn’t let me do this in a single step (how lazy of me).

The Problem

The original code* looked similar in structure to this:

public abstract class Mapper<TDestination>

{

   public static TDestination Map(object source)

   {

      //do mapping here

      return destination;

   }

}

Since Mapper is not a static class, we cannot use resharpers built in “convert static to extension method” refactoring straight up; extension methods can only live in a static class. We could move this method to a static class, say MapperExtensions, such that we can perform “convert static to extension method”, but to do this we also require the generic type parameter TDestination that lives on the Mapper class. There isn’t a refactoring (that I am aware of/could find with a quick google) to add a generic type parameter to a method signature and adding this in by hand would break all my code that invokes this method. We cannot make the Mapper class static either, since it is an abstract class. This was looking like it could be a bit of a pain.

*The example (mapping) is actually contrived – I’ve made up a example here that is representative of the structure of the problem, rather than use the actual code. This was to avoid breaching the IP rules of the company I work for. In an actual mapper, the Map method is more likely to be an instance method rather than static, and since Mapping it is the primary responsibility of the class, it is not advisable for the Map method to be implemented as an extension method.

The Solution

Step 1: Extract Method

First of all, we can use the extract method refactoring to extract the contents of the original method into another method. We can then use this newly created method as a base to make a any further changes (like adding the generic type parameter) without breaking anything that invokes our original code. After this step, we have:

public abstract class Mapper<TDestination>

{

   public static TDestination Map(object source)

   {

      return MapTo<TDestination>(source);

   }

   public static TDestination MapTo<TDestination>(object source)

   {

      //do mapping here

      return destination;

   }

}

Step 2: Move Method

Since we now have a static method with the required generic type parameter, we can now use the “Move Method” refactoring to move MapTo to its new home, the static class MapperExtensions.

Step 3: Convert static to extension method

We’re now all set to use this refactoring – and we’re nearly there!

Step 4: inline method

We can now make the original call to Map an inline method. This will essentially replace all existing calls from using Map to use the MapTo extension method.

The End Result

The finished article now looks like this:

public static class MapperExtensions

{

   public static TDestination MapTo<TDestination>(this object source)

   {

      //do mapping here

      return destination;

   }

}

Now we’re talking!

Advertisements

About craigcav

Craig Cavalier works as a Software Developer for Liquid Frameworks in Houston Tx, developing field ticketing and job management solutions for industrial field service companies.

Posted on August 10, 2009, in Refactoring and tagged , . Bookmark the permalink. Leave a comment.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: