← Назад к вопросам

Как реализовано перетирание в C#?

1.7 Middle🔥 191 комментариев
#ООП и паттерны проектирования#Основы C# и .NET

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое «перетирание» в C#?

В контексте C# термин «перетирание» (или «shadowing») обычно относится к механизму сокрытия членов класса (method/property/field hiding). Это ситуация, когда производный класс объявляет член с тем же именем, что и член в базовом классе, но без полиморфного поведения. В отличие от переопределения (override), сокрытие создаёт новый, независимый член в производном классе, который не участвует в полиморфизме и не вызывается через ссылку на базовый класс.

Ключевое отличие: new vs override

Основное различие между сокрытием (new) и переопределением (override):

  • override – обеспечивает полиморфное поведение. Вызывается метод производного класса, даже если обращение идёт через ссылку на базовый класс.
  • newскрывает унаследованный член. При обращении через ссылку на базовый класс будет вызван метод базового класса; через ссылку на производный – новый метод.

Реализация сокрытия через модификатор new

Сокрытие реализуется с помощью модификатора new в объявлении члена производного класса.

Пример с методами

public class BaseClass
{
    public void Display()
    {
        Console.WriteLine("BaseClass.Display()");
    }
}

public class DerivedClass : BaseClass
{
    // Сокрытие метода Display базового класса
    public new void Display()
    {
        Console.WriteLine("DerivedClass.Display()");
    }
}

class Program
{
    static void Main()
    {
        DerivedClass derived = new DerivedClass();
        BaseClass baseRef = derived; // Приведение к базовому типу

        derived.Display(); // Вывод: DerivedClass.Display()
        baseRef.Display(); // Вывод: BaseClass.Display() (сокрытие!)
    }
}

Пример со свойствами

public class Animal
{
    public virtual string Sound { get; set; } = "Generic sound";
}

public class Dog : Animal
{
    // Сокрытие свойства Sound
    private new string Sound { get; set; } = "Bark";

    public void MakeSound()
    {
        Console.WriteLine(Sound); // Bark
        Console.WriteLine(base.Sound); // Generic sound (обращение к базовому)
    }
}

Особенности и нюансы сокрытия

1. Сокрытие полей

public class Base
{
    public int value = 10;
}

public class Derived : Base
{
    public new string value = "shadowed"; // Другой тип данных!
}

2. Явный вызов базового члена

public class Derived : BaseClass
{
    public new void Display()
    {
        base.Display(); // Вызов скрытого метода базового класса
        Console.WriteLine("Дополнительная логика");
    }
}

3. Сокрытие статических членов

public class MathBase
{
    public static double Pi => 3.14;
}

public class MathDerived : MathBase
{
    public new static double Pi => 3.1415926535; // Сокрытие статического свойства
}

Когда использовать сокрытие (new)?

Полезные сценарии:

  1. Постепенная модернизация – когда нужно изменить сигнатуру или поведение метода, но сохранить обратную совместимость.
  2. Контроль над полиморфизмом – когда метод базового класса не был помечен как virtual, но требуется реализовать аналогичную функциональность.
  3. Специализация в параллельных иерархиях – в шаблонах проектирования, где производные классы могут нуждаться в совершенно другой реализации.

Риски и предупреждения:

BaseClass[] items = { new BaseClass(), new DerivedClass() };
foreach (var item in items)
{
    item.Display(); // Всегда BaseClass.Display() - нет полиморфизма!
}

Сравнение подходов

АспектПереопределение (override)Сокрытие (new)
ПолиморфизмПолностью поддерживаетсяОтсутствует
Связь с базовым классомТесная, логическаяФормальная, только по имени
Вызов через базовую ссылкуМетод производного классаМетод базового класса
ТребованияБазовый член должен быть virtual/abstractБазовый член может быть любым
БезопасностьКонтроль компиляторомМеньше контроля, возможны ошибки

Рекомендации по использованию

  1. Отдавайте предпочтение переопределению (override), если нужен полиморфизм.
  2. Используйте new осознанно – это нарушает принцип подстановки Барбары Лисков (LSP).
  3. Комментируйте причины использования сокрытия в коде.
  4. Рассмотрите альтернативы – переименование метода, шаблон «Стратегия», композицию вместо наследования.

Заключение

Сокрытие членов класса (shadowing или «перетирание») в C# – мощный, но потенциально опасный механизм, реализуемый через модификатор new. Он позволяет создавать в производных классах члены с именами, идентичными базовым, но без установления полиморфной связи. Хотя этот подход может быть полезен в отдельных сценариях (например, при рефакторинге унаследованного кода), его следует применять с осторожностью из-за нарушения интуитивно ожидаемого полиморфного поведения и связанных с этим рисков. В большинстве случаев более предпочтительным является классическое переопределение (override) с использованием виртуальных членов.

Как реализовано перетирание в C#? | PrepBro