Метод расширения

Перейти к навигацииПерейти к поиску

Метод расширения (англ. extension method) в программировании — метод, добавляемый к существующему классу (типу) в месте, отличном от модуля объявления класса. Синтаксический сахар для модуля расширения был введён в C# 3.0 и VB.NET.

Метод расширения не следует путать с относящему к наследованию понятием расширения метода (англ. method extension), существующего в языках CLOS, Smalltalk, Beta, при котором метод суперкласса вызывается до, во время или после вызова метода класса[1].

Реализация в C#

Следующий пример показывает метод расширения, определённый для класса System.String (в языке C# имеет псевдоним string). Заметим, что он определён внутри невложенного и ненастраиваемого статичного класса[2]:

namespace ExtensionMethods
{
    public static class MyExtensions
    {
        // метод WordCount принимает на вход строку, возвращает число слов, т.е. число подстрок, разделённых пробелом, точкой или вопросительным знаком.
        public static int WordCount(this string str)
        {
            return str.Split(new char[] { ' ', '.', '?', '!' }, 
                             StringSplitOptions.RemoveEmptyEntries).Length;
        }
    }   
}

/* Метод-расширение WordCount появится в области видимости, если подключить соответствующее пространство имён: */
using ExtensionMethods;

/* Теперь его можно вызвать: */
string s = "Hello Extension Methods";
int i = s.WordCount(); // i получит значение 3
int j = "Съешь же ещё этих мягких французских булок, да выпей чаю.".WordCount(); // j получит значение 10

В сравнении с обычным методом, метод расширения статичен, а первый параметр содержит после this целевой класс и переменную целевого класса, после чего могут следовать параметры метода[3].

В C# метод расширения имеет доступ только к публичным членам класса. Другим ограничением является то, что если есть и встроенный метод, и расширение, приоритет даётся встроенному методу[3].

Методы расширения широко используются в LINQ. Например, оператор Select является методом расширения интерфейса IEnumerable[4].

Реализация в Visual Basic .NET

В Visual Basic .NET методы расширения позволяют разработчикам добавлять новые возможности типам данных без образования производных типов. Метод расширения может быть только процедурой вида Sub или Function, но не свойством, полем или событием. Первый аргумент метода указывает целевой тип данных для расширения. Методы расширения могут определяться только внутри модулей. Как и в C#, метод экземпляра имеет преимущество перед методом расширения, даже если последний обладает более точной сигнатурой[5].

Реализация в Ruby

Язык Ruby имеет аналогичную C# 3.0 возможность, называемую «открытый класс» (англ. open class)[6].

class TestClass
  def method1
  end

  def method2
  end
end

test = TestClass.new
test.method1
test.method2

class TestClass
  def method3
  end
end

test.method3

Кроме того, метод расширения можно добавить не ко всему классу, а только конкретному экземпляру. Более того, в JRuby можно добавить метод к классу из Java[6]. В Ruby, если есть и встроенный метод, и расширение, приоритет дается расширенному методу.

Реализация в других языках

В распространённых динамических языках (JavaScript, Perl, Python, Ruby) механизм метода расширения уже давно может быть реализован (со всеми мерами предосторожности) путём «обезьяньего патча»[7].

В стандарте C++23 методов расширения всё ещё нет, но оставлено место под них — this-параметры[8].

Примечания

  1. Gardner, 2002, p. 63.
  2. Extension Methods (C# Programming Guide). Дата обращения: 15 февраля 2012. Архивировано 17 февраля 2012 года.
  3. 1 2 Liberty, Xie, 2007.
  4. C# extension methods. Дата обращения: 20 сентября 2014. Архивировано 24 сентября 2014 года.
  5. Bai, 2012.
  6. 1 2 Neal Ford, Are Open Classes Evil? Архивная копия от 4 марта 2016 на Wayback Machine, 2007
  7. Monkeypatching For Humans Архивная копия от 6 сентября 2014 на Wayback Machine, Jeff Atwood, 2008
  8. Deducing this. Дата обращения: 28 июля 2022. Архивировано 12 июля 2022 года.

Литература

  • Liberty, J. and Xie, D. Programming C# 3.0. — O'Reilly Media, 2007. — P. 294-297. — 608 p. — ISBN 9780596554880.
  • Papa, J. Data-Driven Services with Silverlight 2. — O'Reilly Media, 2008. — P. 12-14. — 368 p. — ISBN 9780596554422.
  • Gardner, T.A. Inheritance Relationships for Disciplined Software Construction. — Springer, 2002. — ISBN 9781852334673.
  • Bai, Y. Practical Database Programming with Visual Basic.NET. — Wiley, 2012. — P. 229-232. — 900 p. — ISBN 9781118249826.

Ссылки