Метод расширения
Метод расширения (англ. 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++ механизм методов расширения находится на этапе рассмотрения комитетом по стандартизации языка [8].
Примечания
- Gardner, 2002, p. 63.
- Extension Methods (C# Programming Guide)
- Liberty, Xie, 2007.
- C# extension methods
- Bai, 2012.
- Neal Ford, Are Open Classes Evil?, 2007
- Monkeypatching For Humans, Jeff Atwood, 2008
- Bjarne Stroustrup. Call syntax: x.f(y) vs. f(x,y) (11 октября 2014).
Литература
- 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.