Определение методов расширения
Пишите статические методы с модификатором this.
«Определение методов расширения» — бесплатный урок C# Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C# Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C# Academy содержит 4 уроков всего.
Что такое метод расширения
Метод расширения позволяет добавлять новые методы к существующему типу, не изменяя его и не создавая производный тип. Вы вызываете его так, будто это метод экземпляра, но на самом деле это специальный static-метод.
Расширения особенно полезны, когда исходный код типа (например, string или int) Вам не принадлежит, но Вы хотите добавить ему удобное новое поведение.
Три требования
Чтобы объявить метод расширения, нужны: статический класс, статический метод и первый параметр, отмеченный ключевым словом this. Параметр this задаёт тип, который Вы расширяете.
using System;
public static class StringExtensions
{
public static int WordCount(this string text)
{
if (string.IsNullOrWhiteSpace(text)) return 0;
return text.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Length;
}
}
public class Program
{
public static void Main()
{
string sentence = "the quick brown fox";
Console.WriteLine(sentence.WordCount());
}
}Вызов как метода экземпляра
Хотя WordCount является статическим методом, Вы вызываете его как sentence.WordCount(). За кулисами компилятор преобразует этот вызов в StringExtensions.WordCount(sentence).
using System;
using System.Linq;
public static class StringExtensions
{
public static string Repeat(this string text, int times)
{
return string.Concat(Enumerable.Repeat(text, times));
}
}
public class Program
{
public static void Main()
{
// These two lines do exactly the same thing
Console.WriteLine("ab".Repeat(3));
Console.WriteLine(StringExtensions.Repeat("ab", 3));
}
}Параметр получателя получает экземпляр
Значение слева от точки становится параметром this. После него можно добавить другие параметры, и вызывающий код передаёт их обычным способом.
using System;
public static class IntExtensions
{
public static bool IsBetween(this int value, int low, int high)
{
return value >= low && value <= high;
}
}
public class Program
{
public static void Main()
{
int age = 25;
Console.WriteLine(age.IsBetween(18, 65));
Console.WriteLine(10.IsBetween(1, 5));
}
}Расширение собственных типов
Расширения предназначены не только для библиотечных типов. Вы также можете расширять собственные классы, что удобно для сохранения чистого основного типа при добавлении вспомогательных возможностей в другом месте.
using System;
public class Money
{
public decimal Amount { get; }
public Money(decimal amount) { Amount = amount; }
}
public static class MoneyExtensions
{
public static string ToUsd(this Money m) => "$" + m.Amount.ToString("0.00");
}
public class Program
{
public static void Main()
{
var price = new Money(19.5m);
Console.WriteLine(price.ToUsd());
}
}Методы расширения не имеют доступа к закрытым членам
Метод расширения — это всего лишь статический метод в другом классе, поэтому он может использовать только открытую (или внутреннюю, если находится в той же сборке) часть типа. Он не может обращаться к закрытым полям.
using System;
public class Counter
{
private int _count;
public int Value => _count;
public void Increment() => _count++;
}
public static class CounterExtensions
{
// Can only use public members like Value and Increment
public static bool IsZero(this Counter c) => c.Value == 0;
}
public class Program
{
public static void Main()
{
var c = new Counter();
Console.WriteLine(c.IsZero());
c.Increment();
Console.WriteLine(c.IsZero());
}
}Объединение методов расширения в цепочки
Поскольку каждое расширение возвращает значение, их можно объединять в плавную цепочку вызовов. Такая запись читается сверху вниз — именно этот стиль используется в LINQ.
using System;
public static class TextExtensions
{
public static string Shout(this string s) => s.ToUpper();
public static string Bang(this string s) => s + "!";
}
public class Program
{
public static void Main()
{
string result = "hello".Shout().Bang();
Console.WriteLine(result);
}
}Пустые значения и методы расширения
В отличие от настоящего вызова метода экземпляра, метод расширения может выполняться даже тогда, когда получатель имеет значение null, поскольку разыменование не происходит, пока Ваш код не обратится к этому значению. Это позволяет писать вспомогательные методы, безопасно работающие с пустыми значениями.
using System;
public static class StringExtensions
{
public static bool IsBlank(this string text)
{
// text may be null here, and that is fine
return string.IsNullOrWhiteSpace(text);
}
}
public class Program
{
public static void Main()
{
string nothing = null;
Console.WriteLine(nothing.IsBlank());
Console.WriteLine("x".IsBlank());
}
}Методы экземпляра имеют приоритет над расширениями
Если существует настоящий метод экземпляра с совпадающей сигнатурой, компилятор всегда предпочитает его методу расширения. Расширения лишь заполняют пробелы, которые тип ещё не покрывает.
using System;
public static class Ext
{
// This will be ignored because string already has ToString()
public static string ToString(this string s, int n) => s + n;
}
public class Program
{
public static void Main()
{
// Resolves to the built-in instance ToString(), not the extension
Console.WriteLine("value: " + "abc".ToString());
}
}Практическая библиотека вспомогательных средств
Объединение связанных расширений в одном статическом классе создаёт аккуратную библиотеку вспомогательных средств. Вот небольшой вспомогательный класс для работы с числами, который можно повторно использовать в разных частях проекта.
using System;
public static class NumberExtensions
{
public static bool IsEven(this int n) => n % 2 == 0;
public static int Squared(this int n) => n * n;
public static double Percent(this int n) => n / 100.0;
}
public class Program
{
public static void Main()
{
Console.WriteLine(4.IsEven());
Console.WriteLine(5.Squared());
Console.WriteLine(50.Percent());
}
}Попробуйте сами
Объедините изученное: создайте один статический класс с несколькими специализированными расширениями и вызывайте их последовательно. Именно так создаются повседневные библиотеки вспомогательных средств.
using System;
public static class StringExtensions
{
public static string Capitalize(this string s)
=> string.IsNullOrEmpty(s) ? s : char.ToUpper(s[0]) + s.Substring(1);
public static string Surround(this string s, char c) => c + s + c;
}
public class Program
{
public static void Main()
{
Console.WriteLine("hello".Capitalize().Surround('*'));
}
}Быстрая проверка
Проверьте, насколько хорошо Вы понимаете объявление методов расширения.
Повторение
Вы узнали, что метод расширения — это static-метод в static-классе, у которого первый параметр использует this. Он вызывается с синтаксисом метода экземпляра, но компилируется в обычный статический вызов.
- Три требования: статический класс, статический метод и первый параметр
this. - Доступны только открытые члены.
- Методы экземпляра всегда имеют приоритет.
- Методы расширения можно объединять в цепочки и даже вызывать для получателей со значением
null.
Часто задаваемые вопросы
Урок «Определение методов расширения» бесплатный?
Да — полный текст урока «Определение методов расширения» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C# Academy, подпишись на CoddyKit PRO. Курс C# Academy содержит 4 уроков всего.
Чему я научусь в уроке «Определение методов расширения»?
Пишите статические методы с модификатором this. Ты практикуешь C# Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать C# Academy?
Предыдущий опыт не требуется. C# Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.
Сколько времени занимает урок «Определение методов расширения»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке C# Academy?
Да. Каждый урок C# Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Определение методов расширения
- Расширение интерфейсов и обобщённых типов
- Выбор метода расширения
- Проектирование хороших расширений