Использование методов расширения - PullRequest
12 голосов
/ 31 декабря 2008

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

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

Ответы [ 9 ]

11 голосов
/ 31 декабря 2008

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

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

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

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

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

instance.SomeExtensionMethod()

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

StaticExtensionMethodClass.SomeExtensionMethod(instance);

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

2 голосов
/ 31 декабря 2008

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

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

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

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/


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

1 голос
/ 05 февраля 2009

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

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

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

против

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

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

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

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

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

1 голос
/ 31 декабря 2008

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

1 голос
/ 31 декабря 2008

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

1 голос
/ 31 декабря 2008

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

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

0 голосов
/ 30 августа 2009

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

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

0 голосов
/ 05 февраля 2009

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

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

0 голосов
/ 31 декабря 2008

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

...