Для чего используется модификатор доступа protected в C#?

«Для чего используется модификатор доступа protected в C#?» — вопрос из категории ООП, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Модификатор protected предоставляет доступ к члену класса (полю, свойству, методу, событию) только из кода внутри самого этого класса и любых производных (наследующих) классов. Это ключевой инструмент для реализации принципа наследования, позволяя скрыть детали реализации от внешнего мира, но оставить возможность их использования и расширения в подклассах.

Пример базового использования:

public class LoggerBase
{
    // Защищенное поле доступно наследникам, но не внешнему коду
    protected string _logFilePath;

    // Защищенный метод для внутренней логики наследников
    protected virtual string FormatMessage(string message)
    {
        return $"[{DateTime.Now}] {message}";
    }

    // Публичный интерфейс, использующий защищенную логику
    public void Log(string message)
    {
        var formattedMessage = FormatMessage(message);
        WriteToFile(formattedMessage);
    }

    private void WriteToFile(string text) { /* ... */ }
}

public class JsonLogger : LoggerBase
{
    public JsonLogger(string path) { _logFilePath = path; } // Доступ к protected-полю

    // Переопределение защищенного метода для изменения поведения
    protected override string FormatMessage(string message)
    {
        return $"{{"timestamp": "{DateTime.Now}", "message": "{message}"}}";
    }
}

// Использование
var logger = new JsonLogger("log.json");
logger.Log("System started"); // Работает
// logger._logFilePath = "new.txt"; // ОШИБКА КОМПИЛЯЦИИ: недоступно извне

Комбинация protected internal: Этот модификатор делает член доступным из любых классов в текущей сборке И из производных классов в других сборках. Это полезно для создания расширяемых библиотек.

Когда использовать protected:

  • При проектировании базовых классов (base classes) и абстрактных классов, предназначенных для наследования.
  • Для создания шаблонного метода (Template Method), где алгоритм определен в базовом классе, а некоторые шаги делегированы защищенным виртуальным методам для переопределения в наследниках.
  • Когда необходимо предоставить наследникам доступ к внутреннему состоянию или вспомогательным методам, не предназначенным для публичного API.

Важно: Чрезмерное использование protected полей может нарушить инкапсуляцию в иерархии наследования. Часто лучше использовать protected свойства или методы вместо прямого доступа к полям.