0Pricing
C# Academy · Урок

Определение методов расширения

Пишите статические методы с модификатором 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 — локальная установка не требуется.

Все уроки этого курса

  1. Определение методов расширения
  2. Расширение интерфейсов и обобщённых типов
  3. Выбор метода расширения
  4. Проектирование хороших расширений
← Назад к C# Academy