0

I'm wondering whether method overloading that will be mainly be there as convenience for the caller should be implemented on the interface or as extension methods? I've looked but I could not find any official guidelines when it comes to methods that are overloaded merely for convenience' sake.

I know that if you own the code you should probably not use extension methods but is there a difference when it comes to methods that are just there for convenience. I feel like they would clutter the interface but maybe that's just me.

Regarding duplicate: My question is more about method overloading when the overloads are there for convenience for the caller and will not differ between implementations

Example implementation with method overloading in the interface:

public interface IFoo
{
    //This feels cluttered since they don't add any new functionality, 
    // they are just here to be convenient for the caller.
    void Bar(int a);
    void Bar(int a, int b);
    void Bar(int a, int b, int c);
}

Example implementation with extension methods:

public interface IFoo
{
    void Bar(int a);
}

public static class FooExtensions
{
    public static void Bar(this IFoo foo, int a, int b)
    {
        //...
    }

    public static void Bar(this IFoo foo, int a, int b, int c)
    {
        //...
    }
}
Joakim Skoog
  • 766
  • 10
  • 23
  • 3
    This feels opinion based... imho the main difference is: if you provide the methods in the interface, then every class _implementing_ the interface _must_ implement them, but is also _free_ to provide a "different than usual" implementation. If you provide it as an extension, then noone else _needs_ to implement them, but also noone can provide their own _overrides_. It's "take it, or leave it/create your own extension (with a different name)". – Corak Jan 18 '19 at 10:13
  • Overloading in your case is definitely better option. Implementation of the interface should be placed in the class that implements it, not in extension. – Marcin Topolewski Jan 18 '19 at 10:13

1 Answers1

4

We should use extension methods if we are quite sure that the methods are the same for the all (including potential) interface implementation:

  public interface IFoo {
    void Bar(int a); 
  } 

  public static class FooExtensions {
    public static void Bar(this IFoo foo, int a, int b) {...}
    public static void Bar(this IFoo foo, int a, int b, int c) {...}
  }

We can implement different Bar(int a) methods

  public MyFoo : IFoo {
    void Bar(int a) { /* MyFoo algorithm here */}
  }

  public MyOtherFoo : IFoo {
    void Bar(int a) { /* some other - MyOtherFoo - algorithm here */}
  }

But Bar(int a, b) as well as Bar(int a, b, c) are still be the same:

  new MyFoo().Bar(1, 2);      // FooExtensions.Bar(IFoo, int, int) called
  new MyOtherFoo().Bar(1, 2); // FooExtensions.Bar(IFoo, int, int) called 

If, say, Bar(int a, int b) can vary from implementation to implementation we have have to add it into interface:

  public interface IFoo {
    void Bar(int a); 
    void Bar(int a, int b); 
  } 

  ...

  public MyFoo : IFoo {
    void Bar(int a)        { /* MyFoo algorithm here */}
    void Bar(int a, int b) { /* MyFoo algorithm here */} 
  }

  public MyOtherFoo : IFoo {
    void Bar(int a)        { /* some other - MyOtherFoo - algorithm here */}
    void Bar(int a, int b) { /* some other - MyOtherFoo - algorithm here */} 
  }

If almost all interface implementations have the same algorithm it'll be boring to put the boiler plate code. However, in C# 8.0 we are going to have a good compromise - default method implmentation, e.g.

  public interface IFoo {
    void Bar(int a); 
    void Bar(int a, int b) {
      /* Default code here */
    } 
  } 

  // uses default code for Bar(int a, int b)
  public MyFoo : IFoo {
    void Bar(int a)        { /* MyFoo algorithm here */}
  }

  // uses its own code for Bar(int a, int b)
  public MyOtherFoo : IFoo {
    void Bar(int a)        { /* some other - MyOtherFoo - algorithm here */}
    void Bar(int a, int b) { /* some other - MyOtherFoo - algorithm here */} 
  }
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
  • This was the answer that I was looking for, thank you! The overloads will never differ from the implementations, they are merely there for convenience so that different callers won't have to transform their data. – Joakim Skoog Jan 18 '19 at 10:38