介面一旦發布即難以修改 (破壞現有實作)。擴充方法允許在不修改介面定義、不修改實作類別的情況下,為介面「新增」方法,解決版本演進難題。
// 定義介面
public interface ILogger
{
void Log(string message);
}
// 擴充方法類別 (必須為 static)
public static class LoggerExtensions
{
// this ILogger 表示擴充 ILogger
public static void LogError(this ILogger logger, string error)
{
logger.Log($"[ERROR] {error}");
}
public static void LogWarning(this ILogger logger, string warning)
{
logger.Log($"[WARN] {warning}");
}
}
// 使用
public class ConsoleLogger : ILogger
{
public void Log(string msg) => Console.WriteLine(msg);
}
var logger = new ConsoleLogger();
logger.LogError("磁碟空間不足"); // 輸出: [ERROR] 磁碟空間不足
logger.LogWarning("記憶體使用率 90%"); // 輸出: [WARN] 記憶體使用率 90%
using 介面即自動啟用擴充方法,無額外引用負擔。public interface ITest { void Do(); }
public static class Ext { public static void Do(this ITest t) => Console.WriteLine("Ext"); }
public class Impl : ITest
{
public void Do() => Console.WriteLine("Impl");
public void DoExt() => Console.WriteLine("Impl.DoExt");
}
// 測試
ITest i = new Impl();
i.Do(); // 輸出: Ext (介面呼叫 → 擴充方法)
((Impl)i).Do(); // 輸出: Impl (類別呼叫 → 實例方法)
i.DoExt(); // 編譯錯誤:ITest 無 DoExt
((Impl)i).DoExt(); // 輸出: Impl.DoExt
規則:實例方法優先於擴充方法。介面型別呼叫解析到擴充方法;具體型別呼叫解析到實例方法。
IEnumerable<T>, IQueryable<T>) 新增輔助方法 (LINQ 即大量使用此模式)