Подтвердить что ты не робот

Использование методов расширения

Когда использование методов расширения имеет смысл? Помогает ли добавление методов расширения к типу влиять на производительность?

Эти вопросы касаются вопроса, который я ранее задал о методах расширения.

4b9b3361

Ответ 1

Когда использование методов расширения имеет смысл?

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

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

Связано ли добавление методов расширения с типом производительности?

Обратите внимание, что метод расширения имеет вид:

instance.SomeExtensionMethod()

скомпилируется в:

StaticExtensionMethodClass.SomeExtensionMethod(instance);

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

Ответ 2

Из моего ответа здесь:

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

Взгляните на следующий пример:

public class extended {
    public int sum() {
        return 7+3+2;
    }
}

public static class extending {
    public static float average(this extended extnd) {
        return extnd.sum() / 3;
    }
}

Как вы видите, класс Extending добавляет метод с именем average к классу Extended. Чтобы получить среднее значение, вы вызываете метод average, так как он относится к классу Extended:

extended ex = new extended();

Console.WriteLine(ex.average());

Ссылка: http://aspguy.wordpress.com/2008/07/03/a-practical-use-of-serialization-and-extension-methods-in-c-30/


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

Ответ 3

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

Вы можете видеть это в том, как LINQ (пространство имен System.Linq и другие) добавляет множество функций ко всем коллекциям.

Ответ 4

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

Ответ 5

В дополнение к другим ответам, методы расширения - отличный способ добавить реализацию котельной пластины к интерфейсам. Например, если вы хотите, чтобы все списки были сортируемыми, добавьте метод расширения для IList<T>.

Вы можете (как уже было сказано) также использовать методы расширения для добавления методов к классам вне вашего контроля; когда-либо хотел использовать метод Reverse() на string? Добавьте один!

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

public static void ThrowIfNull<T>(this T obj, string name) where T : class
{
    if(obj == null) throw new ArgumentNullException(name);
}

В отличие от обычных методов утилиты, им очень легко писать свободные интерфейсы; это одна из причин их существования, т.е. с LINQ:

var foo = source.Where(predicate).OrderBy(selector);

намного читаем, чем:

var foo = Enumerable.OrderBy(Enumerable.Where(source,predicate),selector);

С помощью обычных методов, чтобы использовать первый подход, он должен был бы быть обычным методом экземпляра, который потребовал бы изменений (например) до IEnumerable<T> - нежелательных.

Ответ 6

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

Рассмотрите практически любые функции уровня модуля, которые у вас уже есть в приложении, и что они становятся, когда вы помечаете их как методы расширения. Они становятся возможностью "активного голоса" над "пассивным голосом". Активный голос означает, что код читается так, как будто экземпляр предоставляет свой собственный метод для выполнения конкретной задачи, вместо того, чтобы функция выполняла пассивное действие на нем.

ExtendUnlimitedCredit(AddVIP(tblCustomer, "Bill Gates"))

против.

tblCustomer.AddVIP("Bill Gates").ExtendUnlimitedCredit()

Методы расширения делают это преобразование простым. Устранение вложенных вызовов функций с помощью кода "активного голоса" часто является улучшением. Кроме того, поскольку наш магазин блокирует основные классы, мы могли использовать только вызовы функций вложенных функций до методов расширения.

Другие замечательные вещи о методах расширения:

  • Они делают ваши функции (из-за Intellisense) более открытыми. И если вы предоставили встроенную разметку, описывающую назначение и использование вашей функции, Intellisense даже предоставит полезную подсказку, описывающую метод и его использование для разработчика, который его обнаруживает (просто нажав на точку). Функции, не помеченные как методы расширения, не так легко обнаруживаются, могут не использоваться и, в результате, кто-то другой может придумать свой собственный вкус указанной функции.

  • В то время как вы не можете реализовать метод для интерфейса, метод расширения предлагает альтернативное средство, которое дает внешний вид, который вы сделали.

Ответ 7

Я не знаю никаких последствий для производительности. Использование методов расширения имеет наибольший смысл, когда у вас нет доступа к исходному коду и, следовательно, нельзя напрямую добавить метод в класс, и метод имеет смысл быть реализованным как функция. Это относится к комментарию, который я сделал по вашему предыдущему вопросу, где один другой человек дал образец для метода расширения класса "строка", который вернул bool, исходя из того, была ли строка действительной электронной почтой. Это, ИМО, является примером того, когда НЕ использовать метод расширения, потому что эта функция не является фундаментальной для типа строки. Однако добавление функции Left (int) и Right (int) в "string" имеет смысл.

Ответ 8

Я использую их для повторного использования классов объектной модели. У меня есть группа классов, которые представляют объекты, которые у меня есть в базе данных. Эти классы используются на стороне клиента только для отображения объектов, поэтому основное использование доступа к свойствам.

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 и генерирует эти классы заглушек, представляющие некоторый объект, который у меня есть в базе данных. Единственный подход в этом случае - расширить их.

Ответ 9

Решение второго вопроса: мое эмпирическое правило состоит в том, что метод расширения должен быть "естественным расширением функциональности" в типе или что он должен быть удобной и удобочитаемой частью свободного интерфейса.

Примером "естественного расширения функциональности" является расширение считывателя данных, чтобы вернуть значение по умолчанию, если DBNull будет изменен. Не столь естественным было бы расширение чтения данных для возврата экземпляра объекта, представленного данными в нескольких полях. В последнем случае вы вводите неверные обязанности в плохой объект:).