Методы расширения
Механизм методов расширения лучше всего рассматривать на конкретном примере.
В главе 14 я упоминаю о том, что для управления строками класс
StringBuilder
предлагает меньше методов, чем класс
String
, и это довольно странно, потому
что класс
StringBuilder
является предпочтительнее для управления строками,
так как он изменяем. Допустим, вы хотите определить некоторые отсутствующие
в классе
StringBuilder
методы самостоятельно. Возможно, вы решите определить
собственный метод
IndexOf
:
public static class StringBuilderExtensions {
public static Int32 IndexOf(StringBuilder sb, Char value) {
for (Int32 index = 0; index < sb.Length; index++)
if (sb[index] == value) return index;
return -1;
}
}
После того как метод будет определен, его можно использовать в программах:
// Инициализирующая строка
StringBuilder sb = new StringBuilder("Hello. My name is Jeff.");
// Замена точки восклицательным знаком
// и получение номера символа в первом предложении (5)
Int32 index = StringBuilderExtensions.IndexOf(sb.Replace('.', '!'), '!');
235
Методы.расширения
Этот программный код работает, но в перспективе он не идеален. Во-первых, про-
граммист, желающий получить индекс символа при помощи класса
StringBuilder
,
должен знать о существовании класса
StringBuilderExtensions
. Во-вторых,
программный код не отражает последовательность операторов, представленных
в объекте
StringBuilder
, что усложняет понимание, чтение и сопровождение кода.
Программистам удобнее было бы вызывать сначала метод
Replace
, а затем метод
IndexOf
, но когда вы прочитаете последнюю строчку кода слева направо, первым
в строке окажется
IndexOf
, а затем —
Replace
. Вы можете исправить ситуацию
и сделать поведение программного кода более понятным, написав следующий код:
// Замена точки восклицательным знаком
sb.Replace('.', '!');
// Получение номера символа в первом предложении (5)
Int32 index = StringBuilderExtensions.IndexOf(sb, '!');
Однако здесь возникает третья проблема, затрудняющая понимание логики
кода. Использование класса
StringBuilderExtensions
отвлекает программиста
от выполняемой операции:
IndexOf
. Если бы класс
StringBuilder
определял
собственный метод
IndexOf
, то представленный код можно было бы переписать
следующим образом:
// Замена точки восклицательным знаком
// и получение номера символа в первом предложении (5)
Int32 index = sb.Replace('.', '!').IndexOf('!');
В контексте сопровождения программного кода это выглядит великолепно!
В объекте
StringBuilder
мы заменяем точку восклицательным знаком, а затем
находим индекс этого знака.
А сейчас я попробую объяснить, что именно делают методы расширения. Они
позволяют вам определить статический метод, который вызывается посредством
синтаксиса экземплярного метода. Иначе говоря, мы можем определить собствен-
ный метод
IndexOf
— и три проблемы, упомянутые выше, исчезнут. Для того чтобы
превратить метод
IndexOf
в метод расширения, мы просто добавим ключевое слово
this
перед первым аргументом:
public static class StringBuilderExtensions {
public static Int32 IndexOf(this StringBuilder sb, Char value) {
for (Int32 index = 0; index < sb.Length; index++)
if (sb[index] == value) return index;
return -1;
}
}
Компилятор увидит следующий код:
Int32 index = sb.IndexOf('X');
Сначала он проверит класс
StringBuilder
или все его базовые классы, предо-
ставляющие экземплярные методы с именем
IndexOf
и единственным параметром
236
Do'stlaringiz bilan baham: |