25 July 2007

ReSharper vs C# 3.0 - Extension Methods

I'm going to do several posts about how are we going to support C# 3.0 in ReSharper. I will not dig into much technical details, instead I will discuss end-user experience and product decisions we have to make. These posts are not meant to be description of features, they are rather invitation to discussion - what do you want to see in ReSharper for C# 3.0.

Today I'm going to discuss Extension Methods.

Note: Information, features and ideas contained in this post are preliminary and subject to change in the release version of ReSharper with C# 3.0 support.

In short, extension methods feature provides ability to pseudo-extend some type's public interface via static member. Compiler looks for static methods marked with System.Runtime.CompilerServices.ExtensionAttribute in the static class with the same attribute. It then converts obj.ExtensionMethod(params) into ExtensionClass.ExtensionMethod(obj, params) while compiling. There is also syntactic sugar to mark methods as extensions - you prefix first parameter of ExtensionMethod with "this" keyword:


  public static class ListExtensions
  {
    public static void Process(this List<int> list, int p) {}
  }

As soon as you have instance of List, namespace of ExtensionClass imported into current file and System.Core assembly referenced you can use it as follows:

    void Foo(List<int> list)
    {
      list.Process(1);
    }


What does it mean for ReSharper? Well, besides parsing and resolving, it mostly means updating many features to support extension methods, like parameter information, navigation and search.

There will be a number of context actions, analyses and quick fixes to help with extension methods. For example, you already added "this" to the first parameter of the static member, but still using it in the form of a static method in your code, like this: ListExtensions.Process(list,1). In this case suggestion could be issued to convert to the pseudo-instance form: list.Process(1);

There are also some things that should be done specifically for Extension Methods feature. It would be very handy to have completion feature which lists non-imported extensions and insert using directives when you select one, much like Type Name Completion. Most likely we will extend existing feature to work after "dot" and rename it as "Import Name Completion".

It would be nice to have a refactoring to convert existing static member in a static class into extension method and update all usages to the pseudo-instance form.

When implementing interfaces, ReSharper could also look for extension methods that match interface members and current type, and suggest to use them as default implementation instead of throwing NotImplementedException.

If you have any other ideas about supporting Extension Methods in ReSharper, you are welcome to comment on this post.

4 comments:

Michael Hedgpeth said...

Another idea is you can extract a method into an extension method.

So:
1> bool enoughToProcess;
2> ArrayList elements;
3> enoughToProcess = elements.Count > ProcessingThreshold;

4> if (enoughToProcess) { Process(); }

So you would highlight 2 & 3, do an extract method and have the option to make it an extension method on ArrayList and come up with this:

if (elements.EnoughToProcess) { Process(); }

I think this would naturally give people a use of these features right at the point that it would make sense.

Anonymous said...

When will Resharper get C# 3.0 support? I've been using VS 2008 for a while now, and it's really killing me having Resharper flag all uses and implementations of extension methods as errors!

Please hurry!

Zach Scott said...

I second that motion.

There are a bunch of developers here chomping at the bit to use C# 3.0.

Do you plan to make Re# 3.x.x play nicely with C# 3.0 before adding all the new intentions and refactorings that go with C# 3.0?

I think many people would appreciate that. I know I would.

Cheers,
Zach

Ilya Ryzhenkov said...

I think I will write a post tomorrow about what is going around C# 3.0 and ReSharper.