Це питання щодо методів розширення C # та їх філософії дизайну, тому я вважаю, що найкращим способом відповісти на це питання є цитування документації MSDN про призначення методів розширення :
Методи розширення дозволяють "додавати" методи до існуючих типів без створення нового похідного типу, перекомпіляції чи іншої модифікації вихідного типу. Методи розширення - це особливий вид статичного методу, але вони називаються так, ніби вони були методами екземплярів розширеного типу. Для клієнтського коду, написаного на C #, F # та Visual Basic, немає явної різниці між викликом методу розширення та методів, які фактично визначені у типі.
…
Загалом, ми рекомендуємо застосовувати методи розширення економно та лише тоді, коли це потрібно. Коли це можливо, клієнтський код, який повинен поширювати існуючий тип, повинен це зробити, створивши новий тип, похідний від існуючого типу. Для отримання додаткової інформації див. Спадщина.
Використовуючи метод розширення для розширення типу, вихідний код якого ви не можете змінити, ви ризикуєте, що зміна в реалізації типу призведе до порушення способу розширення.
Якщо ви реалізуєте методи розширення для заданого типу, пам’ятайте наступні моменти:
- Метод розширення ніколи не буде викликатися, якщо він має такий самий підпис, як метод, визначений у типі.
- Методи розширення вводяться в область застосування на рівні простору імен. Наприклад, якщо у вас є кілька статичних класів, які містять методи розширення в єдиному просторі імен, названий
Extensions
ними, всі вони будуть приведені в область застосування using Extensions;
директивою.
Підводячи підсумок, методи розширення призначені для додавання примірних методів до певного типу, навіть коли розробники не можуть це зробити безпосередньо. А оскільки методи екземпляра завжди замінять методи розширення, якщо вони є (якщо вони викликаються за допомогою синтаксису методу екземпляра), це слід робити лише в тому випадку, якщо ви не можете безпосередньо додати метод або розширити клас. *
Іншими словами, метод розширення повинен діяти так само, як і метод екземпляра, оскільки він може в кінцевому підсумку бути створеним методом екземпляра деяким клієнтом. А тому, що метод екземпляра повинен кидатись, якщо об’єкт, на який він викликається, є null
таким, як і метод розширення.
* Як бічна примітка, саме така ситуація зіткнулася з дизайнерами LINQ: коли вийшов C # 3.0, вже було мільйони клієнтів, які користувалися System.Collections.IEnumerable
і System.Collections.Generic.IEnumerable<T>
як у своїх колекціях, так і в foreach
циклі. Ці класи повертаються IEnumerator
об'єкти , які були тільки два методи Current
і MoveNext
, таким чином додаючи додаткові необхідні методи , наприклад, такі , як Count
, Any
і т.д., буде порушувати ці мільйони клієнтів. Отже, щоб забезпечити цю функціональність (тим більше, що вона може бути реалізована в термінах Current
і MoveNext
з відносною легкістю), вони випустили її як методи розширення, які можна застосувати до будь-якого існуючого в даний часIEnumerable
Наприклад, вони також можуть бути реалізовані класами більш ефективними способами. Якби дизайнери C # вирішили випустити LINQ в перший день, це було б запропоновано як екземплярні методи IEnumerable
, і вони, ймовірно, розробили б якусь систему, щоб забезпечити реалізацію цих методів інтерфейсом за замовчуванням.