views:

1234

answers:

11

The new extensions in .Net 3.5 allow functionality to be split out from interfaces.

For instance in .Net 2.0

public interface IHaveChildren {
    string ParentType { get; }
    int ParentId { get; }

    List<IChild> GetChildren()
}

Can (in 3.5) become:

public interface IHaveChildren {
    string ParentType { get; }
    int ParentId { get; }
}

public static class HaveChildrenExtension {
    public static List<IChild> GetChildren( this IHaveChildren ) {
        //logic to get children by parent type and id
        //shared for all classes implementing IHaveChildren 
    }
}

This seems to me to be a better mechanism for many interfaces. They no longer need an abstract base to share this code, and functionally the code works the same. This could make code more maintainable and easier to test.

The only disadvantage being that an abstract bases implementation can be virtual, but can that be worked around (would an instance method hide an extension method with the same name? would it be confusing code to do so?)

Any other reasons not to regularly use this pattern?


Clarification:

Yeah, I see the tendency with extension methods is to end up with them everywhere. I'd be particularly careful having any on .Net value types without a great deal of peer review (I think the only one we have on string is a .SplitToDictionary() - similar to .Split() but taking a key-value delimiter too)

I think there's a whole best practice debate there ;-)

(Incidentally: DannySmurf, your PM sounds scary.)

I'm specifically asking here about using extension methods where previously we had interface methods.


I'm trying to avoid lots of levels of abstract base classes - the classes implementing these models mostly already have base classes. I think this model could be more maintainable and less overly-coupled than adding further object hierarchies.

Is this what MS have done to IEnumerable and IQueryable for Linq?

A: 

One problem I can see is that, in a large company, this pattern could allow the code to become difficult (if not impossible) for anyone to understand and use. If multiple developers are constantly adding their own methods to existing classes, separate from those classes (and, God help us all, to BCL classes even), I could see a code base spinning out of control rather quickly.

Even at my own job, I could see this happening, with my PM's desire to add every bit of code that we work on to either the UI or the data access layer, I could totally see him insisting on 20 or 30 methods being added to System.String that are only tangentially-related to string handling.

DannySmurf
+3  A: 

I think the best thing that extension methods replace are all those utility classes that you find in every project.

At least for now, I feel that any other use of Extension methods would cause confusion in the workplace.

My two bits.

Vaibhav
+6  A: 

Extension methods should be used as just that: extensions. Any crucial structure/design related code or non-trivial operation should be put in an object that is composed into/inherited from a class or interface.

Once another object tries to use the extended one, they won't see the extensions and might have to reimplement/re-reference them again.

The traditional wisdom is that Extension methods should only be used for:

  • utility classes, as Vaibhav mentioned
  • extending sealed 3rd party APIs
Jon Limjap
+1  A: 

Ouch. Please don't extend Interfaces.
An interface is a clean contract that a class should implement, and your usage of said classes must be restricted to what is in the core Interface for this to work correctly.

That is why you always declare the interface as the type instead of the actual class.

IInterface variable = new ImplementingClass();

Right?

If you really need a contract with some added functionality, abstract classes are your friends.

Lars Mæhlum
+2  A: 

There is nothing wrong with extending interfaces, in fact that is how LINQ works to add the extension methods to the collection classes.

That being said, you really should only do this in the case where you need to provide the same functionality across all classes that implement that interface and that functionality is not (and probably should not be) part of the "official" implementation of any derived classes. Extending an interface is also good if it is just impractical to write an extension method for every possible derived type that requires the new functionality.

Scott Dorman
A: 

I see separating the domain/model and UI/view functionality using extension methods as a good thing, especially since they can reside in separate namespaces.

For example:

namespace Model
{
    class Person
    {
        public string Title { get; set; }
        public string FirstName { get; set; }
        public string Surname { get; set; }
    }
}

namespace View
{
    static class PersonExtensions
    {
        public static string FullName(this Model.Person p)
        {
            return p.Title + " " + p.FirstName + " " + p.Surname;
        }

        public static string FormalName(this Model.Person p)
        {
            return p.Title + " " + p.FirstName[0] + ". " + p.Surname;
        }
    }
}

This way extension methods can be used similarly to XAML data templates. You can't access private/protected members of the class but it allows the data abstraction to be maintained without excessive code duplication throughout the application.

Zooba
+1  A: 

I see a lot of people advocating using a base class to share common functionality. Be careful with this - you should favor composition over inheritance. Inheritance should only be used for polymorphism, when it makes sense from a modelling point of view. It is not a good tool for code reuse.

As for the question: Be ware of the limitations when doing this - for example in the code shown, using an extension method to implement GetChildren effectively 'seals' this implementation and doesn't allow any IHaveChildren impl to provide its own if needed. If this is OK, then I dont mind the extension method approach that much. It is not set in stone, and can usually be easily refactored when more flexibility is needed later.

For greater flexibility, using the strategy pattern may be preferable. Something like:

public interface IHaveChildren 
{
    string ParentType { get; }
    int ParentId { get; }
}

public interface IChildIterator
{
    IEnumerable<IChild> GetChildren();
}

public void DefaultChildIterator : IChildIterator
{
    private readonly IHaveChildren _parent;

    public DefaultChildIterator(IHaveChildren parent)
    {
        _parent = parent; 
    }

    public IEnumerable<IChild> GetChildren() 
    { 
        // default child iterator impl
    }
}

public class Node : IHaveChildren, IChildIterator
{ 
    // *snip*

    public IEnumerable<IChild> GetChildren()
    {
        return new DefaultChildIterator(this).GetChildren();
    }
}
Fredrik Kalseth
+3  A: 

I think the judicious use of extension methods put interfaces on a more equatable position with (abstract) base classes.


Versioning. One advantage base classes have over interfaces is that you can easily add new virtual members in a later version, whereas adding members to an interface will break implementers built against the old version of the library. Instead, a new version of the interface with the new members needs to be created, and the library will have to work around or limit access to legacy objects only implementing the original interface.

As a concrete example, the first version of a library might define an interface like so:

public interface INode {
  INode Root { get; }
  List<INode> GetChildren( );
}

Once the library has released, we cannot modify the interface without breaking current users. Instead, in the next release we would need to define a new interface to add additional functionalty:

public interface IChildNode : INode {
  INode Parent { get; }
}

However, only users of the new library will be able to implement the new interface. In order to work with legacy code, we need to adapt the old implementation, which an extension method can handle nicely:

public static class NodeExtensions {
  public INode GetParent( this INode node ) {
    // If the node implements the new interface, call it directly.
    var childNode = node as IChildNode;
    if( !object.ReferenceEquals( childNode, null ) )
      return childNode.Parent;

    // Otherwise, fall back on a default implementation.
    return FindParent( node, node.Root );
  }
}

Now all users of the new library can treat both legacy and modern implementations identically.


Overloads. Another area where extension methods can be useful is in providing overloads for interface methods. You might have a method with several parameters to control its action, of which only the first one or two are important in the 90% case. Since C# does not allow setting default values for parameters, users either have to call the fully parameterized method every time, or every implementation must implement the trivial overloads for the core method.

Instead extension methods can be used to provide the trivial overload implementations:

public interface ILongMethod {
  public bool LongMethod( string s, double d, int i, object o, ... );
}

...
public static LongMethodExtensions {
  public bool LongMethod( this ILongMethod lm, string s, double d ) {
    lm.LongMethod( s, d, 0, null );
  }
  ...
}


Please note that both of these cases are written in terms of the operations provided by the interfaces, and involve trivial or well-known default implementations. That said, you can only inherit from a class once, and the targeted use of extension methods can provide a valuable way to deal with some of the niceties provided by base classes that interfaces lack :)


Edit: A related post by Joe Duffy: Extension methods as default interface method implementations

Emperor XLII
+1  A: 

Rob Connery (Subsonic and MVC Storefront) implemented an IRepository-like pattern in his Storefront application. It's not quite the pattern above, but it does share some similarities.

The data layer returns IQueryable which permits the consuming layer to apply filtering and sorting expression on top of that. The bonus is being able to specify a single GetProducts method, for example, and then decide appropriately in the consuming layer how you want that sorting, filtering or even just a particular range of results.

Not a traditional approach, but very cool and definitely a case of DRY.

objektivs
A: 

I needed to solve something similar: I wanted to have a List<IIDable> passed to the extensions function where IIDable is an interface that has a long getId() function. I tried using GetIds(this List<IIDable> bla) but the compiler didn't allow me to do so. I used templates instead and then type casted inside the function to the interface type. I needed this function for some linq to sql generated classes.

I hope this helps :)

    public static List<long> GetIds<T>(this List<T> original){
        List<long> ret = new List<long>();
        if (original == null)
            return ret;

        try
        {
            foreach (T t in original)
            {
                IIDable idable = (IIDable)t;
                ret.Add(idable.getId());
            }
            return ret;
        }
        catch (Exception)
        {
            throw new Exception("Class calling this extension must implement IIDable interface");
        }
Abdo
+1  A: 

A little bit more.

If multiple interfaces have the same extension method signature, you would need to explicitly convert the caller to one interface type and then call the method. E.g.

((IFirst)this).AmbigousMethod()
Jerry Liu
Agreed, although if you have to do this I suggest that either the interfaces are poorly designed or that your class shouldn't implement both of them.
Keith