Які переваги методів розширення ви виявили? [зачинено]


84

"Невіруючий" C # запитував мене, яка мета методів розширення. Я пояснив, що тоді ви можете додавати нові методи до об’єктів, які вже були визначені, особливо коли ви не володієте / не контролюєте джерело до вихідного об’єкта.

Він підняв запитання "Чому б просто не додати метод до власного класу?" Ми ходили по колу (в хорошому сенсі). Моя загальна відповідь полягає в тому, що це ще один інструмент на стрічці інструментів, і його відповідь - це марне марнотратство інструменту ... але я думав, що отримаю більш "просвітлену" відповідь.

У яких сценаріях ви використовували методи розширення, а не могли (або не повинні) використовувати метод, доданий до власного класу?


2
Я думаю, є безсумнівно вагомі зауваження, які люди можуть зробити (і зробили) на підтримку методів розширення ... але точно не існує сценарію, коли " не міг" використовувати статичні методи замість методів розширення. Методи розширення насправді є просто статичними методами, доступ до яких здійснюється по-іншому. Просто те, про що слід пам’ятати.
Dan Tao

@DanTao, на більш легкій ноті, одне, що робить виклик методом розширення незамінним, це саме їх іменування. Extensions.To(1, 10)є безглуздим і 1.To(10)є описовим. Звичайно, я розумію технічну сторону, про яку ви говорите, просто кажучи. Насправді існують сценарії, коли один " не міг" використовувати підхід розширення замість статичних методів, наприклад, відображення, інший випадок dynamic.
nawfal

Відповіді:


35

Я думаю, що методи розширення дуже допомагають при написанні коду, якщо ви додасте методи розширення до основних типів, ви швидко їх отримаєте в intellisense.

У мене є постачальник формату для форматування розміру файлу . Для його використання мені потрібно написати:

Console.WriteLine(String.Format(new FileSizeFormatProvider(), "{0:fs}", fileSize));

Створюючи метод розширення, я можу написати:

Console.WriteLine(fileSize.ToFileSize());

Чистіше і простіше.


4
більш описова назва вашого методу розширення зробить його ще чистішим. наприклад fileSize.ToFormattedString ();
Девід Альперт,

1
mmm, ToFormattedFizeSize (), можливо, це метод розширення для типу Long, ToFormattedString () не є описовою назвою
Едуардо Кампаньо

3
однак, зроблено пункт. коли я читаю fileSize.ToFileSize (), я запитую, чому дублювання? що це насправді робить? я знаю, що це лише приклад, але описові назви допомагають зробити його чистим і простим.
Девід Альперт,

1
Ви маєте рацію, оскільки з тестами дуже важливо правильно вибрати ім'я
Едуардо Кампаньо

5
Однак це насправді не відповідає на запитання безпосередньо, оскільки наведений вами приклад не повинен бути методом розширення. Ви могли б це зробити LongToFileSize(fileSize), що так само стисло і, можливо, так само чітко.
Дан Тао

83

Тільки перевага методів розширення є читабельність коду. Це воно.

Методи розширення дозволяють зробити це:

foo.bar();

замість цього:

Util.bar(foo);

Зараз у C # є багато подібних речей. Іншими словами, у C # є багато можливостей, які здаються тривіальними і не мають великої вигоди самі по собі. Однак, коли ви починаєте поєднувати ці функції разом, ви починаєте бачити щось трохи більше, ніж сума його частин. LINQ значно виграє від методів розширення, оскільки запити LINQ були б майже нечитабельними без них. LINQ був би можливий без методів розширення, але не практичний.

Методи розширення дуже схожі на часткові класи C #. Самі по собі вони не дуже корисні і здаються дрібницями. Але коли ви починаєте працювати з класом, який потребує згенерованого коду, часткові класи починають мати набагато більше сенсу.


1
Це стає ще більш важливим, якщо ви використовуєте ланцюгові методи, такі як x.Foo (щось) .Bar (somethingelse) .Baz (все ще щось). Це найбільш переважно в методах розширення IEnumerable <> та значно підвищує читабельність
ShuggyCoUk

2
Річ, яку я не отримую, полягає в тому, що foo.bar () підказує мені, що bar () - це метод foo. Тому, коли це не працює, я в кінцевому підсумку шукаю не в тому місці. Я не впевнений, що це насправді покращення читабельності для мене.
Martin Brown

3
Клацнувши правою кнопкою миші на панелі () у VS IDE та вибравши Перейти до визначення, ви потрапите в потрібне місце.
Джефф Мартін

9
Єдиною перевагою 98% мовних конструкцій є читаність коду. Все, що минуло оператора відділення, етикетку, перехід і збільшення, є для полегшення вашого життя.
Джованні Гальбо

2
Це не зовсім так, бувають ситуації, коли методи розширення є єдиним способом розширення класу. Окрім герметичних класів, я використовую їх у досить унікальній ситуації. Дивіться мій пост нижче.
Едвін Джарвіс,

34

Не забувайте інструментальні засоби! Коли ви додаєте метод розширення M для типу Foo, ви отримуєте 'M' у списку інтелісенсів Foo (припускаючи, що клас розширення знаходиться в області дії). Це робить "М" набагато простішим, ніж MyClass.M (Foo, ...).

Зрештою, це просто синтаксичний цукор для інших статичних методів, але як придбання будинку: "місце розташування, місце розташування!" Якщо він зависає на типі, люди знайдуть!


2
У цьому також є невеликий негатив: методи розширення (наприклад, методи System.Linq заповнюють автозаповнення IntelliSense довшим списком, що ускладнює навігацію.
Джаред Апдайк,

@Jared: ... але лише якщо ви імпортували простір імен, де знаходяться методи розширення, тож ви насправді маєте невеликий ступінь контролю над цим "забрудненням IntelliSense". По-друге, не забуваймо, що в BCL існують класи (такі як String), які постачаються з досить довгим списком методів екземпляра, тому ця проблема не є специфічною для методів розширення.
stakx - більше не вносить вклад

29

Ще дві переваги методів розширення, з якими я стикався:

  • Свободний інтерфейс може бути інкапсульований у статичний клас методів розширення, таким чином досягаючи розділення проблем між основним класом та його вільними розширеннями; Я бачив, що досягнення більшої ремонтопридатності.
  • Методи розширення можуть бути відключені від інтерфейсів, тим самим дозволяючи вказати контракт (через інтерфейс) та відповідну серію поведінки на основі інтерфейсу (за допомогою методів розширення), знову пропонуючи розділення проблем. Прикладом є розширення Linq методи , такі як Select(...), Where(...)і т.д. Hung вимиканняIEnumerable<T> інтерфейсу.

1
Ви можете навести кілька прикладів коду для обох пунктів, щоб допомогти їм краще зрозуміти? Здається, це цікава точка зору.
RBT

так, приклад для 2-го пункту був би непоганий.
Іні

26

Одне з найкращих застосувань для методів розширення - це можливість:

  1. Розширити функціонал на сторонніх об'єктах (комерційних чи внутрішніх для моєї компанії, але керованих окремою групою), які в багатьох випадках будуть позначені sealed .
  2. Створіть функціональність за замовчуванням для інтерфейсів без необхідності реалізовувати абстрактний клас

Візьмемо для прикладу IEnumerable<T> . Хоча він багатий методами розширення, мені здавалося прикро, що він не реалізував загальний метод ForEach. Отже, я зробив свій власний:

public void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action)
{
    foreach ( var o in enumerable )
    {
        action(o);
    }
}

Вуаля, всі мої IEnumerable<T>об'єкти, незалежно від типу реалізації, і чи писав я це чи ні, чи хтось інший тепер мав ForEachметод, додавши відповідний оператор "using" у мій код.


3
+1 Мені подобається це розширення, я написав таке саме, як воно. Так дуже корисно
Маслоу

10
Зверніть увагу, що метод повинен бути статичним. Я пропоную прочитати blogs.msdn.com/ericlippert/archive/2009/05/18/… перед тим, як прийняти рішення про використання цього розширення.
TrueWill

Причина, чому впровадження методу розширення ForEach на IEnumerable не оцінена - blogs.msdn.microsoft.com/ericlippert/2009/05/18/…
RBT

12

Однією з основних причин використання методів розширення є LINQ. Без методів розширення багато чого з того, що ви можете зробити в LINQ, було б дуже важко. Методи розширення Where (), Містить (), Select означає, що до існуючих типів додається набагато більше функціональних можливостей, не змінюючи їх структури.


4
це не "одна з", його причина для методів розширення.
gbjbaanb

3
Як так? Це одна з багатьох причин наявності методів розширення, а не єдина вимога. Я можу використовувати методи розширення без використання LINQ.
Ray Booysen

Я думаю, він мав на увазі, що це була причина їх створення, але так, він робить це так, ніби вони є єдиним правильним використанням для них.
Брент Ріттенхаус,

9

Існує безліч відповідей про переваги методів розширень; як щодо того, щоб усунути недоліки ?

Найбільшим недоліком є ​​те, що немає помилки компілятора або попередження, якщо у вас є звичайний метод і метод розширення з однаковим підписом в тому ж контексті.

Припустимо, ви створюєте метод розширення, що застосовується до певного класу. Потім пізніше хтось створює метод з ідентичним підписом на цьому класі.

Ваш код буде скомпільовано, і ви навіть не можете отримати помилку під час виконання. Але ви вже не використовуєте той самий код, що і раніше.


1
4. Подумайте двічі, перш ніж розширювати типи, які вам не належать . Якщо ви пишете методи розширення лише для типів, якими ви володієте, то вам ніколи не доведеться турбуватися про те, що ваші розширення будуть порушені внаслідок змін до типу розширення. З іншого боку, якщо ви поширюєте інші типи людей, ви, по суті, перебуваєте в їхній владі.
DavidRR

1
... Як варіант, ви можете мінімізувати цей ризик, вибравши назви, які навряд чи будуть використовуватися кимось іншим, або мінімізуючи загальну кількість визначених вами методів розширення (тобто зменшення площі поверхні). Одним із методів для цього може бути написання одного методу розширення, який перетворює базовий об'єкт на інший тип, який контролюється вами.
DavidRR

Методи розширення (Керівництво з програмування на C #) : Загалом, ви, ймовірно, будете викликати методи розширення набагато частіше, ніж впроваджувати власні.
DavidRR

8

Вільні інтерфейси та чутливість до контексту, як продемонстрував Грег Янг на CodeBetter


4

Мій особистий аргумент щодо методів розширення полягає в тому, що вони дуже добре вписуються в дизайн ООП: розглянемо простий метод

bool empty = String.IsNullOrEmpty (myString)

в порівнянні з

bool empty = myString.IsNullOrEmpty ();

Я не бачу, що ваш приклад має відношення до ООП. Що ви маєте на увазі?
Andrew Hare

1
"здається", що метод належить об'єкту
Bluenuance

3
Це поганий приклад (може кинути NullReferenceException), але він на правильному шляху. Кращим прикладом може бути заміна Math.abs (-4) на щось на зразок -4.abs ();
Програміст поза законом

15
наскільки мені відомо (і на мій досвід, якщо пам'ять не зраджує), myString.IsNullOrEmpty () не потрібно кидати NullReferenceException, оскільки методи розширення не вимагають екземпляра об'єкта для запуску.
Девід Альперт

1
Я особисто не прихильник методів розширення, які призначені для роботи з нульовим екземпляром - читачеві це здається одним, а потім робить щось інше.
Марк Сімпсон

4

Вище є безліч чудових відповідей про те, які методи розширення дозволяють вам робити.

Моя коротка відповідь - вони майже усувають потребу у фабриках.

Я лише зазначу, що вони не є новою концепцією, і одна з найбільших перевірок їх полягає в тому, що вони є вбивчою особливістю в Objective-C ( категорії ). Вони додають стільки гнучкості розробці, що базується на фреймворках, що NeXT стала основними користувачами фінансових моделей NSA та Wall Street.

REALbasic також впроваджує їх як розширені методи, і вони мали подібне застосування там, спрощуючи розробку.


4

Я хотів би підтримати інші відповіді тут, які згадують покращену читабельність коду як важливу причину методів розширення. Я продемонструю це з двох аспектів цього: ланцюжок методів проти вкладених викликів методів та захаращення запиту LINQ безглуздими статичними іменами класів.


Візьмемо цей запит LINQ як приклад:

numbers.Where(x => x > 0).Select(x => -x)

Обидва Whereі - Selectце методи розширення, визначені в статичному класі Enumerable. Отже, якби методів розширення не існувало, і це були звичайні статичні методи, останній рядок коду по суті мав би виглядати так:

Enumerable.Select(Enumerable.Where(numbers, x => x > 0), x => -x)

Подивіться, наскільки грізніший цей запит.


По-друге, якби ви зараз хотіли представити власний оператор запитів, у вас, природно, не було б можливості визначити його всередині Enumerableстатичного класу, як і всі інші стандартні оператори запитів, оскільки Enumerableвін знаходиться в рамках, і ви не маєте контролю над цим класом. Тому вам доведеться визначити власний статичний клас, що містить методи розширення. Тоді ви можете отримати такі запити, як цей:

Enumerable.Select(MyEnumerableExtensions.RemoveNegativeNumbers(numbers), x => -x)
//                ^^^^^^^^^^^^^^^^^^^^^^
//                different class name that has zero informational value
//                and, as with 'Enumerable.xxxxxx', only obstructs the
//                query's actual meaning.

3

Це правда, що ви можете додати свій метод (розширення) безпосередньо до свого класу. Але не всі класи ви пишете вами. Класи з основної бібліотеки або сторонніх бібліотек часто закриті, і отримати синтатичний цукор без методів розширення було б неможливо. Але пам’ятайте, методи розширення подібно до (статичних) автономних методів, наприклад, наприклад. c ++


3

Методи розширення також можуть допомогти зберегти ваші класи та залежності від класу в чистоті. Наприклад, вам може знадобитися метод Bar () для класу Foo скрізь, де використовується Foo. Однак вам може знадобитися метод .ToXml () в іншій збірці і лише для цієї збірки. У цьому випадку ви можете додати необхідні залежності System.Xml та / або System.Xml.Linq до цієї збірки, а не до початкової збірки.

Переваги: ​​залежності у збірці класу, що визначається, зменшуються лише до найнеобхідніших потреб, а інші споживаючі збірки не зможуть використовувати метод ToXml (). Дивіться цю презентацію PDC для подальшого використання.


3

Я згоден, що методи розширення збільшують читабельність коду, але насправді це не що інше, як статичні допоміжні методи.

IMO з використанням методів розширення для додавання поведінки до ваших класів може бути:

Заплутане: Програмісти можуть вважати, що методи є частиною розширеного типу, отже, не розуміючи, чому методи відпадають, коли простір імен розширення не імпортується.

Антипаттерн: Ви вирішили додати поведінку до типів у вашій структурі, використовуючи методи розширення, а потім відправити їх якійсь особі, яка перейде в модульне тестування. Тепер він застряг у фреймворку, що містить купу методів, які він не може підробити.


Це неправда, що розробник застряг у купу методів, які він не може підробити. Ці методи розширення зрештою викликають якийсь метод класу / інтерфейсу, який вони розширюють, і цей метод може бути перехоплений, якщо він віртуальний.
Patrik Hägne

1
Ну, тоді це залежить від того, що зроблено в методі розширення. Скажімо, ви використовуєте надані методи розширення в інтерфейсі, навіть не знаючи, що це методи розширення. Тоді ви не хочете підробляти виклик методу до інтерфейсу, але ви розумієте, що насправді ви використовуєте статичний метод. Виклик статичного методу не може бути перехоплений підробленим API-процесором на основі проксі, тому ваш єдиний варіант - роздумати про метод розширення, щоб з’ясувати, які методи насправді підробляти. Тим не менше, в поєднанні з модульним тестуванням ІМО.
HaraldV

2

Методи розширення насправді є включенням .NET рефактора "Ввести іноземний метод" з книги Мартіна Фаулера (аж до підпису методу). Вони мають в основному однакові переваги та підводні камені. У розділі, присвяченому цьому рефактору, він говорить, що вони працюють навколо того, коли ви не можете змінити клас, який повинен насправді володіти методом.


2
+1, але зауважте, що ви можете використовувати методи розширення і з інтерфейсами.
TrueWill

2

В основному я розглядаю методи розширення як визнання того, що, можливо, вони не повинні забороняти безкоштовні функції.

У спільноті С ++ часто вважається гарною практикою ООП віддавати перевагу вільним функціям, що не є членами, перед членами, оскільки ці функції не порушують інкапсуляцію, отримуючи доступ до приватних членів, які їм не потрібні. Методи розширення, здається, обхідний спосіб досягти того самого. Тобто чистіший синтаксис для статичних функцій, які не мають доступу до приватних членів.

Методи розширення - це не що інше, як синтаксичний цукор, але я не бачу ніякої шкоди у їх використанні.


2
  • Intellisense на самому об'єкті, замість того, щоб викликати якусь потворну функцію корисності
  • Для функцій перетворення можна змінити "XToY (X x)" на "ToY (цей X x)", що призводить до досить x.ToY () замість потворного XToY (x).
  • Розширюйте класи, на які у вас немає контролю
  • Розширити функціональність класів, коли небажано додавати методи до самих класів. Наприклад, ви можете зробити бізнес-об'єкти простими та вільними від логіки, а також додати конкретну бізнес-логіку з потворними залежностями в методи розширення

2

Я використовую їх для повторного використання класів об’єктної моделі. У мене є купа класів, які представляють об'єкти, які я маю в базі даних. Ці класи використовуються на стороні клієнта лише для відображення об'єктів, тому основним використанням є доступ до властивостей.

public class Stock {
   public Code { get; private set; }
   public Name { get; private set; }
}

Через такий шаблон використання я не хочу мати методи бізнес-логіки в цих класах, тому я роблю кожну бізнес-логіку методом розширення.

public static class StockExtender {
    public static List <Quote> GetQuotesByDate(this Stock s, DateTime date)
    {...}
}

Таким чином я можу використовувати ті самі класи для обробки бізнес-логіки та для відображення інтерфейсу користувача, не перевантажуючи сторону клієнта непотрібним кодом.

Цікавою річчю цього рішення є те, що мої класи об’єктної моделі динамічно генеруються за допомогою Mono.Cecil , тому було б дуже важко додати методи бізнес-логіки, навіть якби я хотів. У мене є компілятор, який читає файли визначень XML і генерує ці класи заглушок, що представляють якийсь об'єкт, який я маю в базі даних. Єдиний підхід у цьому випадку - продовжити їх.


1
Для цього ви можете використовувати часткові класи ...
JJoos


1

У своєму останньому проекті я використовував метод розширення для приєднання методів Validate () до бізнес-об'єктів. Я обґрунтував це тим, що бізнес-об’єкти, де об’єкти передачі даних, що піддаються серіалізації, і будуть використовуватися в різних доменах, як там, де загальні організації електронної комерції, такі як продукт, клієнт, торговець тощо. У різних доменах правила бізнесу можуть бути різними, тому я інкапсулював свої пізньообмежена логіка перевірки у методі Validate, приєднаному до базового класу моїх об'єктів передачі даних. Сподіваюся, це має сенс :)


1

Один із випадків, коли методи розширення були досить корисними, був у клієнтській програмі, яка використовує веб-сервіси ASMX. Через серіалізацію типи повернення веб-методів не містять жодних методів (на клієнті доступні лише загальнодоступні властивості цих типів).

Методи розширення дозволяють використовувати для додавання функціональності (на стороні клієнта) до типів, що повертаються веб-методами, без необхідності створювати ще одну об'єктну модель або численні класи обгортки на стороні клієнта.


1

Методи розширення можуть бути використані для створення свого роду міксину в C #.

Це, в свою чергу, забезпечує кращий поділ питань щодо ортогональних концепцій. Погляньте на цю відповідь як приклад.

Це також може бути використано для включення ролей у C #, концепцію, центральну для архітектури DCI .


1

Також пам’ятайте, що методи розширення були додані як спосіб, який допомагає запиту Linq бути більш читабельним при використанні у їх стилі C #.

Ці 2 афектації абсолютно рівнозначні, однак перший набагато читабельніший (і розрив у готовності, звичайно, збільшиться із збільшенням кількості методів, прикутих до ланцюга).

int n1 = new List<int> {1,2,3}.Where(i => i % 2 != 0).Last();

int n2 = Enumerable.Last(Enumerable.Where(new List<int> {1,2,3}, i => i % 2 != 0));

Зверніть увагу, що повноцінним синтаксисом має бути навіть:

int n1 = new List<int> {1,2,3}.Where<int>(i => i % 2 != 0).Last<int>();

int n2 = Enumerable.Last<int>(Enumerable.Where<int>(new List<int> {1,2,3}, i => i % 2 != 0));

Випадково, параметри типу Whereі Lastне потрібно чітко згадувати, оскільки їх можна ввести завдяки наявності першого параметра цих двох методів (параметра, який вводиться ключовим словомthis та робить їх методами розширення).

Цей момент, очевидно, є перевагою (серед інших) методів розширення, і ви можете скористатися ним у кожному подібному сценарії, де задіяний ланцюжок методів.

Особливо, це більш елегантний і переконливий спосіб, який я виявив, що метод базового класу викликається будь-яким підкласом і повертає сильно набране посилання на цей підклас (із типом підкласу).

Приклад (добре, цей сценарій абсолютно сирний): після доброї ночі тварина відкриває очі, потім кричить; кожна тварина відкриває очі однаково, тоді як собака гавкає, а качка квакає.

public abstract class Animal
{
    //some code common to all animals
}

public static class AnimalExtension
{
    public static TAnimal OpenTheEyes<TAnimal>(this TAnimal animal) where TAnimal : Animal
    {
        //Some code to flutter one's eyelashes and then open wide
        return animal; //returning a self reference to allow method chaining
    }
}

public class Dog : Animal
{
    public void Bark() { /* ... */ }
}

public class Duck : Animal
{
    public void Kwak() { /* ... */ }
}

class Program
{
    static void Main(string[] args)
    {
        Dog Goofy = new Dog();
        Duck Donald = new Duck();
        Goofy.OpenTheEyes().Bark(); //*1
        Donald.OpenTheEyes().Kwak(); //*2
    }
}

Концептуально OpenTheEyesповинен бути Animalметод, але він потім повертає екземпляр абстрактного класу Animal, який не знає конкретних методів підкласу , як Barkабо Duckчи будь інший . Потім два рядки, коментовані як * 1 та * 2, спричинять помилку компіляції.

Але завдяки методам розширення ми можемо мати свого роду "базовий метод, який знає тип підкласу, за яким він називається".

Зверніть увагу, що простий загальний метод міг би виконати цю роботу, але набагато незручнішим чином:

public abstract class Animal
{
    //some code common to all animals

    public TAnimal OpenTheEyes<TAnimal>() where TAnimal : Animal
    {
        //Some code to flutter one's eyelashes and then open wide
        return (TAnimal)this; //returning a self reference to allow method chaining
    }
}

Цього разу жодного параметра і, отже, жодного можливого виводу типу повернення. Дзвінок може бути не чим іншим, як:

Goofy.OpenTheEyes<Dog>().Bark();
Donald.OpenTheEyes<Duck>().Kwak();

... що може значно зважити код, якщо задіяно більше ланцюжків (особливо знаючи, що параметр type завжди буде <Dog>в рядку Гуфі та в рядку <Duck>Дональда ...)


1
Вперше я коли-небудь бачив "квак". Це правопис, який поширений в іншій країні? Єдиний спосіб, коли я коли-небудь бачив, як це пишеться, - це «шарлатанка».
Брент Ріттенхаус,

0

Я маю сказати про це лише одне слово: МАЙТАБІЛЬНІСТЬ - це ключ до використання методів розширення


4
Я думаю, що вам може знадобитися більше одного слова, тому що я не розумію, що це означає.
Програміст-поза законом

2
Я б насправді сказав, що це аргумент проти методів розширення. Одним із ризиків методів розширення є те, що вони можуть бути скрізь, створені кожною людиною. Wildgrow може трапитися, якщо не використовувати обережно.
Борис Калленс

Ви можете легко знайти всі посилання, використовуючи EM. Крім того, для глобальної зміни одного методу ви можете зробити це лише з одного місця
Тамір

0

Я думаю, що методи розширення допомагають писати код, який є зрозумілішим.

Замість того, щоб розміщувати новий метод у своєму класі, як запропонував ваш друг, ви помістили його у простір імен ExtensionMethods. Таким чином ви підтримуєте логічне почуття порядку у своєму класі. Методи, які насправді не стосуються безпосередньо вашого класу, не будуть його захаращувати.

Я відчуваю, що методи розширення роблять ваш код чіткішим та доречнішим.


0

Це дозволяє вашому редактору / IDE робити автоматичне заповнення пропозицій розумно.


0

Я люблю їх за створення html. Часто є розділи, які використовуються неодноразово або генеруються рекурсивно, де функція корисна, але в іншому випадку порушить потік програми.

        HTML_Out.Append("<ul>");
        foreach (var i in items)
            if (i.Description != "")
            {
                HTML_Out.Append("<li>")
                    .AppendAnchor(new string[]{ urlRoot, i.Description_Norm }, i.Description)
                    .Append("<div>")
                    .AppendImage(iconDir, i.Icon, i.Description)
                    .Append(i.Categories.ToHTML(i.Description_Norm, urlRoot)).Append("</div></li>");
            }

        return HTML_Out.Append("</ul>").ToString();

Бувають також ситуації, коли об’єкту потрібна власна логіка, щоб бути підготовленою до вихідних HTML-методів - методи розширення дозволяють додавати цю функціональність без змішування презентації та логіки в класі.


0

Я виявив, що методи розширення корисні для узгодження вкладених загальних аргументів.

Це звучить трохи дивно - але скажімо, у нас є загальний клас MyGenericClass<TList>, і ми знаємо, що сам TList є загальним (наприклад,List<T> ), я не думаю, що існує спосіб витягти вкладене "T" зі Списку без будь-якого розширення методи або статичні допоміжні методи. Якщо ми маємо у своєму розпорядженні лише статичні допоміжні методи, це (а) негарно, і (б) змусить нас перемістити функціональність, яка належить до класу, у зовнішнє розташування.

наприклад, щоб отримати типи в кортежі та перетворити їх у підпис методу, ми можемо використовувати методи розширення:

public class Tuple { }
public class Tuple<T0> : Tuple { }
public class Tuple<T0, T1> : Tuple<T0> { }

public class Caller<TTuple> where TTuple : Tuple { /* ... */ }

public static class CallerExtensions
{
     public static void Call<T0>(this Caller<Tuple<T0>> caller, T0 p0) { /* ... */ }

     public static void Call<T0, T1>(this Caller<Tuple<T0, T1>> caller, T0 p0, T1 p1) { /* ... */ }
}

new Caller<Tuple<int>>().Call(10);
new Caller<Tuple<string, int>>().Call("Hello", 10);

Тим не менш, я не впевнений, де має бути розділювальна лінія - коли метод повинен бути методом розширення, а коли він повинен бути статичним допоміжним методом? Будь-які думки?


0

На моєму екрані є зони введення, і всі повинні застосовувати стандартну поведінку незалежно від їх точного типу (текстові поля, прапорці тощо). Вони не можуть успадкувати загальний базовий клас, оскільки кожен тип зони введення вже походить від певного класу (TextInputBox тощо).

Можливо, піднявшись в ієрахію успадкування, я міг би знайти спільного предка, наприклад, скажімо WebControl, але я не розробив фреймворк-клас WebControl, і він не викриває того, що мені потрібно.

За допомогою методу розширення я можу:

1) розширити клас WebControl, а потім отримати мою уніфіковану стандартну поведінку на всіх моїх класах введення

2) в якості альтернативи зробити всі мої класи похідними від інтерфейсу, скажімо IInputZone, і розширити цей інтерфейс методами. Тепер я зможу викликати методи розширень, пов’язані з інтерфейсом, у всіх моїх зонах введення. Таким чином я домігся свого роду багаторазового успадкування, оскільки мої вхідні зони вже походять від декількох базових класів.


0

Існує так багато чудових прикладів методів розширення, особливо щодо IEnumerables, як розміщено вище.

наприклад, якщо у мене є IEnumerable<myObject>я можу створити і метод розширення дляIEnumerable<myObject>

mylist List<myObject>;

... створити список

mylist.DisplayInMyWay();

Без методів розширення доведеться викликати:

myDisplayMethod(myOldArray); // can create more nexted brackets.

ще один чудовий приклад - це створення кругового зв’язаного списку миттєво!

Я можу взяти за це кредит!

круговий зв’язаний список із використанням методів розширення

Тепер об'єднайте їх і за допомогою методів розширення код читається наступним чином.

myNode.NextOrFirst().DisplayInMyWay();

а не

DisplayInMyWay(NextOrFirst(myNode)).

з використанням методів розширення Він акуратніший і легший для читання та більш орієнтований на об’єкти. також дуже близько до:

myNode.Next.DoSomething()

Покажіть це своєму колезі! :)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.