Extension interface patterns

15,599

Solution 1

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

Solution 2

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

Solution 3

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.

Solution 4

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.

Solution 5

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()
Share:
15,599

Related videos on Youtube

Keith
Author by

Keith

Keith Henry Chief Software Architect, building offline-first and responsive applications in the recruitment industry. I'm also on Linked In. Email me on Google's email, my address is ForenameSurname.

Updated on April 17, 2022

Comments

  • Keith
    Keith about 2 years

    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 the 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 a 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 has done to IEnumerable and IQueryable for Linq?

  • Keith
    Keith over 14 years
    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.
  • Admin
    Admin over 11 years
    I also like this approach zooba, however I went along the lines of a partial class, where the partial held all of the "extensions".