Какие преимущества методов расширения вы обнаружили? [закрыто]

84

«Неверующий» в C # спрашивал меня, какова цель методов расширения. Я объяснил, что затем вы можете добавить новые методы к уже определенным объектам, особенно если вы не владеете / не управляете источником исходного объекта.

Он поднял вопрос: «Почему бы просто не добавить метод в свой класс?» Мы ходим кругом (в хорошем смысле). Мой общий ответ состоит в том, что это еще один инструмент в наборе инструментов, и он отвечает, что это бесполезная трата инструмента ... но я думал, что получу более «просвещенный» ответ.

В каких сценариях вы использовали методы расширения, которые не могли (или не должны были использовать) использовать метод, добавленный в ваш собственный класс?

Джерри
источник
2
Я думаю, что есть определенно веские аргументы, которые люди могут сделать (и сделали) в поддержку методов расширения ... но определенно не существует сценария, в котором " нельзя было бы" использовать статические методы вместо методов расширения. Методы расширения - это просто статические методы, доступ к которым осуществляется по-другому. Просто нужно иметь в виду.
Дэн Тао
@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
ммм, 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 (something) .Bar (somethingelse) .Baz (stillmoresomething). Это наиболее распространено в методах расширения IEnumerable <> и значительно повышает удобочитаемость
ShuggyCoUk
2
Я не понимаю, что foo.bar () подсказывает мне, что bar () - это метод foo. Поэтому, когда это не срабатывает, я ищу не в том месте. Я не уверен, что для меня это действительно улучшение читабельности.
Мартин Браун
3
Щелчок правой кнопкой мыши по панели () в VS IDE и выбор «Перейти к определению» приведет вас в нужное место.
Джефф Мартин
9
Единственное преимущество 98% языковых конструкций - читаемость кода. Все, кроме оператора ветвления, метки, перехода и приращения, должно сделать вашу жизнь немного проще.
Джованни Гальбо,
2
Это не совсем так, в некоторых ситуациях методы расширения - единственный способ расширить класс. Помимо закрытых классов, я использую их в довольно уникальной ситуации. Смотрите мой пост ниже.
Эдвин Джарвис
34

Не забывайте инструменты! Когда вы добавляете метод расширения M к типу Foo, вы получаете «M» в списке intellisense Foo (при условии, что класс расширения входит в область видимости). Это значительно упрощает поиск "M", чем MyClass.M (Foo, ...).

В конце концов, это просто синтаксический сахар для статических методов в другом месте, но как покупка дома: «местоположение, местоположение, местоположение!» Если на типе зависнет, люди найдут!

Брайан
источник
2
У этого также есть небольшой минус: методы расширения (например, из System.Linq заполняют автозаполнение IntelliSense более длинным списком, что немного затрудняет навигацию.
Джаред Апдайк,
@Jared: ... но только если вы импортировали пространство имен, в котором находятся методы расширения, так что у вас есть небольшая степень контроля над этим «загрязнением IntelliSense». Во-вторых, давайте не будем забывать, что в BCL есть классы (например, String), которые идут с довольно длинным списком методов экземпляра, поэтому эта проблема не является специфической для методов расширения.
stakx - больше не вносит вклад
29

Еще два преимущества методов расширения, с которыми я столкнулся:

  • Свободный интерфейс может быть инкапсулирован в статический класс методов расширения, таким образом достигается разделение задач между основным классом и его плавными расширениями; Я видел, что добился большей ремонтопригодности.
  • Методы расширения могут быть отключены от интерфейсов, что позволяет вам указать контракт (через интерфейс) и связанную серию поведения на основе интерфейса (через методы расширения), снова предлагая разделение задач. Примером являются методы расширения Linq, такие как Select(...), Where(...)и т. Д. Повешенные на IEnumerable<T>интерфейсе.
Дэвид Альперт
источник
1
Не могли бы вы процитировать несколько примеров кода для обоих пунктов, чтобы помочь им лучше понять? Это интересная точка зрения.
RBT
да, пример для 2-го пункта был бы неплохим.
Ini
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 (), Contains (), Select означают, что к существующим типам добавляется гораздо больше функций без изменения их структуры.

оборота Рэй Буйсен
источник
4
это не «один из», это причина для методов расширения.
gbjbaanb
3
Как же так? Это одна из многих причин наличия методов расширения, а не единственное требование. Я могу использовать методы расширения без использования LINQ.
Ray Booysen
Я думаю, он имел в виду, что это была причина, по которой они были созданы, но да, он говорит, что они - единственное правильное использование для них.
Брент Риттенхаус
9

Есть множество ответов о преимуществах методов расширения; как насчет устранения недостатков ?

Самым большим недостатком является отсутствие ошибки или предупреждения компилятора, если у вас есть обычный метод и метод расширения с одинаковой сигнатурой в одном контексте.

Предположим, вы создали метод расширения, применяемый к определенному классу. Позже кто-то создает метод с идентичной подписью для самого этого класса.

Ваш код будет компилироваться, и вы даже можете не получить ошибку во время выполнения. Но вы больше не используете тот же код, что и раньше.

Райан Ланди
источник
1
4. Подумайте дважды, прежде чем расширять типы, которыми вы не владеете . Если вы пишете методы расширения только для принадлежащих вам типов, то вам никогда не придется беспокоиться о том, что ваши расширения будут нарушены из-за изменений в расширяемом типе. С другой стороны, если вы расширяете типы других людей, вы, по сути, находитесь в их власти.
DavidRR
1
... В качестве альтернативы, вы можете минимизировать этот риск, выбрав имена, которые вряд ли будут использоваться кем-то другим, или минимизируя общее количество методов расширения, которые вы определяете (т.е. уменьшая площадь поверхности). Один из способов сделать это может заключаться в написании одного метода расширения, который преобразует базовый объект в другой тип, контролируемый вами.
DavidRR
Методы расширения (Руководство по программированию на C #) : в общем, вы, вероятно, будете вызывать методы расширения гораздо чаще, чем реализовывать свои собственные.
DavidRR
8

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

cgreeno
источник
4

Мой личный аргумент в пользу методов расширения заключается в том, что они очень хорошо вписываются в дизайн ООП: рассмотрите простой метод

bool empty = String.IsNullOrEmpty (myString)

в сравнении с

bool empty = myString.IsNullOrEmpty ();
Синий цвет
источник
Я не понимаю, какое отношение ваш пример имеет к ООП. Что вы имеете в виду?
Эндрю Хэйр
1
«кажется», что метод принадлежит объекту
Bluenuance
3
Это плохой пример (может вызвать исключение NullReferenceException), но он на правильном пути. Лучшим примером может быть замена Math.abs (-4) чем-то вроде -4.abs ();
Outlaw Programmer
15
насколько мне известно (и по моему опыту, если память не изменяет), myString.IsNullOrEmpty () не нужно генерировать исключение NullReferenceException, потому что методы расширения не требуют экземпляра объекта для срабатывания.
Дэвид Алперт
1
Я лично не поклонник методов расширения, которые предназначены для работы с нулевым экземпляром - читателю это кажется одним, но затем делает что-то другое.
Марк Симпсон
4

Выше есть куча отличных ответов о том, какие методы расширения позволяют вам делать.

Мой короткий ответ: они почти исключают необходимость в заводах.

Я просто отмечу, что это не новая концепция, и одна из главных их проверок заключается в том, что они являются убийственной функцией в Objective-C ( категориях ). Они добавляют такую ​​гибкость к разработке на основе фреймворков, что NeXT имеет в качестве основных пользователей NSA и специалистов по финансовому моделированию с Уолл-стрит.

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.
stakx - больше не участвует
источник
3

Это правда, что вы можете добавить свой (расширенный) метод прямо в свой класс. Но не все классы написаны вами. Классы из основной библиотеки или сторонних библиотек часто закрыты, и было бы невозможно получить синтаксический сахар без методов расширения. Но помните, что методы расширения похожи на (статические) автономные методы, например. c ++

Шильдмейер
источник
3

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

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

user29439
источник
3

Я согласен с тем, что методы расширения увеличивают читаемость кода, но на самом деле это не что иное, как статические вспомогательные методы.

IMO, использующий методы расширения для добавления поведения в ваши классы, может быть:

Сбивает с толку: программисты могут полагать, что методы являются частью расширенного типа, поэтому не понимают, почему методы исчезают, когда пространство имен-расширений не импортируется.

Антипаттерн: вы решаете добавить поведение к типам в своей структуре, используя методы расширения, а затем отправляете их какому-то человеку, который выполняет модульное тестирование. Теперь он застрял в среде, содержащей кучу методов, которые он не может подделать.

HaraldV
источник
Неверно, что разработчик придерживается множества методов, которые он не может подделать. Эти методы расширения в конечном итоге вызывают какой-либо метод в классе / интерфейсе, который они расширяют, и этот метод может быть перехвачен, учитывая, что он виртуальный.
Патрик Хэгне
1
Ну, тогда это зависит от того, что сделано в методе расширения. Допустим, вы используете предоставленные методы расширения в интерфейсе, даже не зная, что они являются методами расширения. Тогда вам не нужно подделывать вызов метода интерфейса, но вы понимаете, что на самом деле вызываете статический метод. Вызов статического метода не может быть перехвачен API-интерфейсом для подделки на основе прокси, поэтому единственный вариант - выполнить отражение в методе расширения, чтобы выяснить, какие методы на самом деле подделывать. По-прежнему антипаттерн в сочетании с модульным тестированием IMO.
HaraldV
2

Методы расширения на самом деле являются воплощением в .NET рефакторинга «Введение внешнего метода» из Книги Мартина Фаулера (вплоть до сигнатуры метода). Они имеют в основном те же преимущества и недостатки. В разделе об этом рефакторинге он говорит, что это обходной путь, когда вы не можете изменить класс, который действительно должен владеть методом.

Джейсон Пуньон
источник
2
+1, но учтите, что вы также можете использовать методы расширения с интерфейсами.
TrueWill
2

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

В сообществе C ++ часто считается хорошей практикой ООП отдавать предпочтение свободным функциям, не являющимся членами, а не членам, потому что эти функции не нарушают инкапсуляцию, получая доступ к частным членам, которые им не нужны. Методы расширения кажутся окольными путями к тому же. То есть более чистый синтаксис для статических функций, у которых нет доступа к закрытым членам.

Методы расширения - это не что иное, как синтаксический сахар, но я не вижу в их использовании никакого вреда.

Jalf
источник
2
  • Intellisense на самом объекте вместо вызова какой-то уродливой служебной функции
  • Для функций преобразования можно изменить «XToY (X x)» на «ToY (this 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. Из-за сериализации возвращаемые типы веб-методов не содержат никаких методов (на клиенте доступны только общедоступные свойства этих типов).

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

M4N
источник
1

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

Это, в свою очередь, обеспечивает лучшее разделение проблем ортогональных концепций. Взгляните на этот ответ в качестве примера.

Это также можно использовать для включения ролей в C # - концепции, лежащей в основе архитектуры DCI .

Жордау
источник
1

Также помните, что методы расширения были добавлены как способ сделать запрос Linq более читабельным при использовании в их стиле C #.

Эти две модификации абсолютно эквивалентны, но первая гораздо более читабельна (и разрыв в читаемости, конечно, увеличится с увеличением количества связанных методов).

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

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

Сситра
источник
1
Впервые увидел квак. Распространено ли это написание в другой стране? Единственный способ, которым я когда-либо встречал это слово - «шарлатан».
Брент Риттенхаус
0

Я могу сказать об этом только одно слово: ПОДДЕРЖИВАЕМОСТЬ это ключ к использованию методов расширения.

Тамир
источник
4
Я думаю, вам может понадобиться больше одного слова, потому что я не понимаю, что это значит.
Outlaw Programmer
2
Я бы сказал, что это аргумент против методов расширения. Один из рисков методов расширения состоит в том, что они могут быть созданы где угодно и созданы кем угодно. Wildgrow может произойти, если не использовать его осторожно.
Boris Callens
Вы можете легко найти все ссылки, когда используете 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()

Покажи это своему коллеге! :)

Грегор
источник