Ответ
В C# существует шесть модификаторов доступа, которые определяют область видимости и доступность типов (классов, структур, интерфейсов) и их членов (полей, свойств, методов).
| Модификатор | Доступность | Область применения по умолчанию |
|---|---|---|
public |
Не ограничена. Доступен из любого кода в той же сборке (assembly) или в других сборках, которые на нее ссылаются. | Члены интерфейса, перечисления. |
private |
Доступен только внутри объявляющего типа (класса или структуры). | Члены класса и структуры. |
protected |
Доступен внутри объявляющего типа и во всех производных (наследующих) классах. Производный класс может находиться в другой сборке. | - |
internal |
Доступен из любого кода в той же сборке, но не из других сборок. | Типы (классы, структуры) без явного модификатора. |
protected internal |
Объединение protected ИЛИ internal. Доступен: 1) из кода в той же сборке, 2) из производных классов (даже в других сборках). |
- |
private protected (C# 7.2+) |
Пересечение protected И internal. Доступен только из производных классов, которые находятся в той же сборке. |
- |
Практические примеры и сценарии использования:
// Файл: AssemblyA.dll
public class BaseClass
{
public int PublicField; // Виден всем.
private int _privateField; // Виден только внутри BaseClass.
protected int ProtectedField; // Виден в BaseClass и DerivedClass (даже в другом DLL).
internal int InternalField; // Виден во всей AssemblyA.dll.
protected internal int ProtIntField; // Виден в AssemblyA.dll И в DerivedClass из любого DLL.
private protected int PrivProtField; // Виден ТОЛЬКО в BaseClass и DerivedClass внутри AssemblyA.dll.
}
internal class InternalClass { } // Класс виден только внутри AssemblyA.dll.
// Файл: AssemblyB.dll (ссылается на AssemblyA.dll)
public class DerivedClass : BaseClass
{
public void Demo()
{
PublicField = 1; // OK
// _privateField = 2; // ОШИБКА: недоступно
ProtectedField = 3; // OK (наследование)
// InternalField = 4; // ОШИБКА: другая сборка
ProtIntField = 5; // OK (наследование работает)
// PrivProtField = 6; // ОШИБКА: другая сборка (нарушено условие "private protected")
}
}
// В другом классе AssemblyB.dll
class AnotherClass
{
void Demo()
{
var obj = new BaseClass();
obj.PublicField = 1; // OK
// obj.ProtectedField = 2; // ОШИБКА: нет наследования
// obj.InternalField = 3; // ОШИБКА: другая сборка
// obj.ProtIntField = 4; // ОШИБКА: другая сборка И нет наследования
}
}
Рекомендации:
- Соблюдайте принцип минимального доступа: начинайте с
privateи расширяйте видимость только при необходимости. publicинтерфейс класса должен быть минимальным и стабильным.- Используйте
internalдля скрытия служебных типов и методов, которые не должны быть частью публичного API вашей библиотеки. private protectedполезен в больших проектах для создания "семейного" доступа внутри одной сборки.
Ответ 18+ 🔞
Ну, вот смотри, в C# есть эти шесть модификаторов доступа, которые, по сути, решают, кто и куда может совать свои грязные ручонки к твоим классам и полям. Это как уровни допуска на секретный объект, только для кода.
Вот они, эти модификаторы, смотри, разложу по полочкам:
| Модификатор | Кто может лезть? | Где применяется, если не указать? |
|---|---|---|
public |
Абсолютно все, кому не лень. Из своей сборки, из чужой — всем похую, бери и пользуйся. | Члены интерфейсов и перечислений. |
private |
Только внутри того класса или структуры, где объявил. Всё, точка. Как будто на двери замок повесил. | Члены классов и структур. |
protected |
Сам класс плюс все его дети-наследники, даже если они в другой сборке живут. Семейное дело, понимаешь? | - |
internal |
Любой код внутри этой же сборки. Для внешнего мира — как будто этого кода не существует. | Типы (классы, структуры), если явно не указать. |
protected internal |
Это как ИЛИ. Доступно либо из той же сборки, либо наследникам откуда угодно. Широкая душа, блядь. | - |
private protected (C# 7.2+) |
А это уже И. Доступно только наследникам, и только если они в той же сборке. Узкий семейный круг, епта. | - |
А теперь, сука, пример, чтобы вообще всё встало на свои места:
// Файл: AssemblyA.dll
public class BaseClass
{
public int PublicField; // Виден всем, как хуй с горы.
private int _privateField; // Виден только тут. Свой секрет.
protected int ProtectedField; // Мне и моим детям.
internal int InternalField; // Всем своим в этой сборке.
protected internal int ProtIntField; // Или своим в сборке, или детям откуда угодно.
private protected int PrivProtField; // Только детям, которые тут же, в этой сборке. Больше никому.
}
internal class InternalClass { } // Этот класс снаружи сборки — просто призрак, его нет.
// Файл: AssemblyB.dll (тыкнули ссылку на AssemblyA.dll)
public class DerivedClass : BaseClass
{
public void Demo()
{
PublicField = 1; // Окей, это публичное.
// _privateField = 2; // Нихуя! Это папино личное, тебе не светит.
ProtectedField = 3; // Окей, ты же наследник, семья.
// InternalField = 4; // Бля, нет! Ты уже в другой сборке, это internal.
ProtIntField = 5; // Окей! Ты наследник (protected часть сработала).
// PrivProtField = 6; // А вот тут облом. Ты наследник, но из другой сборки. private protected говорит "нет".
}
}
// Просто какой-то левый класс в AssemblyB.dll
class AnotherClass
{
void Demo()
{
var obj = new BaseClass();
obj.PublicField = 1; // Окей, публичное.
// obj.ProtectedField = 2; // Не, дружок, ты не родственник.
// obj.InternalField = 3; // И не земляк по сборке.
// obj.ProtIntField = 4; // И не то, и не другое. Иди нахуй.
}
}
Итог, блядь, и главные правила:
- Принцип минимального доступа — твой друг. Начинай всегда с
private. Зачем светить на весь мир то, что нужно только твоему классу? Расширяешь доступ только когда реально приперло. publicинтерфейс делай маленьким и надёжным. Это лицо твоего класса, его не каждый день меняют.internal— твоя палочка-выручалочка, чтобы спрятать служебную хуйню от пользователей твоей библиотеки. Пусть думают, что там магия.private protected— штука специфичная. Полезно в больших проектах внутри одной сборки, когда хочешь дать доступ только по семейной линии и никому больше.
Видео-ответы
▶
▶
▶
▶
▶
▶
▶