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

В чём разница между protected и internal?

1.3 Junior🔥 181 комментариев
#ООП и паттерны проектирования#Основы C# и .NET

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

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

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

Различие между модификаторами доступа protected и internal в C#

Модификаторы доступа protected и internal в C# представляют два принципиально разных подхода к управлению видимостью членов класса, хотя оба являются менее строгими, чем private, но более ограничивающими, чем public. Ключевое различие заключается в направлении доступа: protected регулирует доступ по иерархии наследования, а internal — по граниницам сборки (assembly).

Ключевые характеристики protected

Модификатор protected разрешает доступ:

  1. Текущему классу, где объявлен член (как и private)
  2. Производным классам (наследникам), независимо от того, в какой сборке они находятся
public class BaseClass
{
    protected int protectedField = 10;
    
    protected void ProtectedMethod()
    {
        Console.WriteLine("Protected method");
    }
}

public class DerivedClass : BaseClass
{
    public void AccessProtectedMember()
    {
        // Доступ разрешен, так как это производный класс
        Console.WriteLine(protectedField);
        ProtectedMethod();
    }
}

public class UnrelatedClass
{
    public void TryAccess()
    {
        BaseClass obj = new BaseClass();
        // ОШИБКА КОМПИЛЯЦИИ: нет доступа к protected членам
        // obj.protectedField = 20;
    }
}

Ключевые характеристики internal

Модификатор internal разрешает доступ:

  1. Любому коду в той же сборке (assembly)
  2. Не предоставляет доступ производным классам из других сборок
// Assembly1.dll
public class DataProcessor
{
    internal string configuration = "DefaultConfig";
    
    internal void ProcessInternal()
    {
        Console.WriteLine("Internal processing");
    }
    
    public void PublicMethod()
    {
        // Внутри сборки можно обращаться к internal членам
        ProcessInternal();
    }
}

// Тот же Assembly1.dll
public class AnotherClassInSameAssembly
{
    public void UseDataProcessor()
    {
        DataProcessor processor = new DataProcessor();
        // ДОСТУП РАЗРЕШЕН: та же сборка
        processor.configuration = "NewConfig";
        processor.ProcessInternal();
    }
}

Сравнительная таблица

Критерийprotectedinternal
Основной принципНаследованиеСборка (assembly)
Доступ из текущего классаДаДа
Доступ из производных классовДа (из любой сборки)Только если в той же сборке
Доступ из других классов той же сборкиНет (если нет наследования)Да
Доступ из других сборокТолько через наследованиеНет
Типичное применениеДля создания расширяемых API, шаблонных методовДля скрытия реализации внутри библиотеки

Комбинированные модификаторы

C# поддерживает комбинации этих модификаторов для более точного контроля:

// protected internal: доступен из производных классов ИЛИ из той же сборки
protected internal string CombinedMember;

// private protected (C# 7.2+): доступен только производным классам В ТОЙ ЖЕ СБОРКЕ
private protected string StrictlyInheritedMember;

Практические сценарии использования

Для protected:

  • Базовые реализации в абстрактных классах, которые должны быть доступны наследникам
  • Виртуальные методы и свойства для переопределения в производных классах
  • Шаблонный метод (Template Method) паттерн, где часть алгоритма определяется в базовом классе

Для internal:

  • Скрытие служебных методов и классов внутри библиотеки
  • Внутренние API, которые не должны быть публичными, но нужны для взаимодействия между компонентами сборки
  • Модульное тестирование внутренней реализации без экспозиции наружу
  • Реализация паттернов вроде фабрик, которые должны быть доступны только внутри сборки

Важные нюансы

  1. Internal и границы сборки: Одна сборка может содержать несколько проектов через InternalsVisibleTo, что позволяет открывать internal-члены для тестовых или дружественных сборок:
[assembly: InternalsVisibleTo("MyTests")]
[assembly: InternalsVisibleTo("FriendAssembly")]
  1. Наследование и internal: Класс может наследоваться от internal-класса только внутри той же сборки.

  2. Переопределение методов: При переопределении виртуальных методов нельзя изменить модификатор доступа, кроме случаев, когда переопределение идет с protected на protected internal в той же сборке.

В заключение, выбор между protected и internal зависит от архитектурной цели: если вам нужно предоставить доступ наследникам (даже из других библиотек) — используйте protected; если нужно ограничить видимость в рамках библиотеки, но разрешить свободное использование внутри нее — выбирайте internal.