扩展和接口一起启用 DRY 代码和类似 mixin 的功能

扩展方法使你可以通过仅在接口本身中包含核心所需功能来简化接口定义,并允许你将方便方法和重载定义为扩展方法。具有较少方法的接口在新类中更容易实现。将重载保持为扩展而不是将它们直接包含在接口中可以使你免于将样板代码复制到每个实现中,从而帮助你保持代码干燥。这实际上类似于 C#不支持的 mixin 模式。

System.Linq.EnumerableIEnumerable<T> 的扩展就是一个很好的例子。IEnumerable<T> 只需要实现类来实现两个方法:泛型和非泛型 GetEnumerator()。但是 System.Linq.Enumerable 提供了无数有用的实用工具作为扩展,可以简单明了地消费 IEnumerable<T>

以下是一个非常简单的界面,带有作为扩展提供的便利重载。

public interface ITimeFormatter
{
   string Format(TimeSpan span);
}

public static class TimeFormatter
{
    // Provide an overload to *all* implementers of ITimeFormatter.
    public static string Format(
        this ITimeFormatter formatter,
        int millisecondsSpan)
        => formatter.Format(TimeSpan.FromMilliseconds(millisecondsSpan));
}

// Implementations only need to provide one method. Very easy to
// write additional implementations.
public class SecondsTimeFormatter : ITimeFormatter
{
   public string Format(TimeSpan span)
   {
       return $"{(int)span.TotalSeconds}s";
   }
}

class Program
{
    static void Main(string[] args)
    {
        var formatter = new SecondsTimeFormatter();
        // Callers get two method overloads!
        Console.WriteLine($"4500ms is rougly {formatter.Format(4500)}");
        var span = TimeSpan.FromSeconds(5);
        Console.WriteLine($"{span} is formatted as {formatter.Format(span)}");
    }
}