扩展方法与重载

Extension methods vs overloading

我想知道方法重载主要是作为调用者的 便利 应该在接口上实现还是作为扩展方法实现?我已经看过了,但我找不到任何官方指南来说明仅仅为了方便而重载的方法。

我知道,如果您拥有代码,您可能不应该使用扩展方法,但是为了方便而使用的方法有什么不同。我觉得他们会弄乱界面,但也许这就是我。

关于重复:我的问题更多是关于方法重载,当重载存在是为了方便调用者并且在实现之间没有区别时

接口中方法重载的示例实现:

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);
}

使用扩展方法的示例实现:

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)
    {
        //...
    }
}

我们应该使用扩展方法,如果我们非常确定这些方法对于所有相同(包括潜在的)接口实现:

  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) {...}
  }

我们可以实现不同的Bar(int a)方法

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

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

但是Bar(int a, b)Bar(int a, b, c)还是一样的:

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

如果,比方说,Bar(int a, int b) 可以 因实现而异,我们必须将其添加到接口中:

  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 */} 
  }

如果几乎所有接口实现都具有相同的算法,那么放置样板代码会很无聊。但是,在 C# 8.0 中,我们将有一个很好的折衷方案——默认方法实现,例如

  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 */} 
  }