Найти в Дзене
TechLead Insights

C# и модификаторы: когда показывать, а когда прятать в C#

Модификаторы доступа в C# определяют видимость и область действия типов и членов типов (классов, структур, методов, свойств и т.д.). Рассмотрим каждый из них и приведем примеры, а также обсудим возможные проблемы при неправильном использовании. Описание: Доступен отовсюду, без ограничений. Пример: В фильме "Звёздные войны" - информация о Звезде Смерти стала публичной благодаря украденным чертежам. Теперь любая сторона может узнать об этом супероружии. Когда использовать: public class SpaceShip
{
public string Model { get; set; }
public void Fly()
{
Console.WriteLine("The spaceship is flying!");
}
} Описание: Доступен только внутри самого класса и производных классов. Пример: В "Король Лев" - Муфаса делится своими знаниями и мудростью только с Симбой, но не с другими животными. Когда использовать: public class Animal
{
protected void Eat()
{
Console.WriteLine("The animal is eating!");
}
}
public class Lion : Animal
{
public void Hunt()
Оглавление

Модификаторы доступа в C# определяют видимость и область действия типов и членов типов (классов, структур, методов, свойств и т.д.). Рассмотрим каждый из них и приведем примеры, а также обсудим возможные проблемы при неправильном использовании.

1. public

Описание: Доступен отовсюду, без ограничений.

Пример: В фильме "Звёздные войны" - информация о Звезде Смерти стала публичной благодаря украденным чертежам. Теперь любая сторона может узнать об этом супероружии.

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

  • Когда необходимо, чтобы член класса был доступен везде, где он используется.
  • Примеры: публичные API методы, общедоступные библиотеки.

public class SpaceShip
{
public string Model { get; set; }
public void Fly()
{
Console.WriteLine("The spaceship is flying!");
}
}

2. protected

Описание: Доступен только внутри самого класса и производных классов. Пример: В "Король Лев" - Муфаса делится своими знаниями и мудростью только с Симбой, но не с другими животными.

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

  • Когда необходимо, чтобы член класса был доступен только для наследуемых классов.
  • Примеры: методы, которые должны быть переопределены в подклассах.

public class Animal
{
protected void Eat()
{
Console.WriteLine("The animal is eating!");
}
}

public class Lion : Animal
{
public void Hunt()
{
Eat(); // Доступен в наследуемом классе
Console.WriteLine("The lion is hunting!");
}
}

3. internal

Описание: Доступен только в пределах текущей сборки (assembly).

Пример: В фильме "Мстители" - информация о месте нахождения ЩИТа доступна только членам команды.

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

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

internal class Shield
{
internal void Protect()
{
Console.WriteLine("Shield is activated!");
}
}

4. private

Описание: Доступен только внутри самого класса.

Пример: В фильме "Интерстеллар" - дневник Купера доступен только ему самому и не может быть прочитан никем другим.

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

  • Когда необходимо полностью скрыть реализацию от других классов.
  • Примеры: инкапсулированные данные, которые не должны быть доступны извне.

public class Diary
{
private string content = "This is a secret.";

private void ReadContent()
{
Console.WriteLine(content);
}
}

5. file

Описание: Доступен только внутри файла исходного кода, в котором он объявлен. Пример: В фильме "Назад в будущее" - записи доктора Брауна о машине времени доступны только ему и Марти в пределах его лаборатории (в данном случае, это аналогично файлу кода).

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

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

file class LocalHelper
{
public void Assist()
{
Console.WriteLine("Assisting...");
}
}

Проблемы при неправильном выборе модификаторов доступа

Рассмотрим использовать все модификаторы доступа в одном примере. Для этого представим сценарий с разработкой игры.

Пример сценария: "Ролевая игра (RPG) с магами и замками"

В этой игре у нас есть класс Wizard (Маг), который содержит различные методы и свойства с различными уровнями доступа. Мы создадим его таким образом, чтобы продемонстрировать все модификаторы доступа:

  1. public: Открытые методы и свойства, доступные всем (например, для вызова заклинаний).
  2. protected: Защищенные методы и свойства, доступные только наследуемым классам (например, скрытые способности).
  3. internal: Методы и свойства, доступные только в пределах сборки (например, управление маной, которая используется только в данной игре).
  4. private: Закрытые методы и свойства, доступные только внутри самого класса (например, личная информация мага).
  5. file: Вспомогательный класс, используемый только внутри файла (например, внутренняя логика расчета урона).

public class Wizard
{
// Публичное свойство для имени мага
public string Name { get; set; }

// Приватное поле для личной информации мага
private string secretIdentity;

// Защищенное свойство для магической энергии (мана)
protected int Mana { get; set; }

// Внутренний метод для восстановления маны

internal void RestoreMana(int amount)
{
Mana += amount;
Console.WriteLine($"{Name} restored {amount} mana.");
}

// Приватный метод для подготовки заклинания
private void PrepareSpell(string spell)
{
Console.WriteLine($"{Name} is preparing {spell}...");
}

// Публичный метод для кастования заклинания

public void CastSpell(string spell)
{
PrepareSpell(spell);
Console.WriteLine($"{Name} casts {spell}!");
}

// Конструктор для установки имени и личной информации
public Wizard(string name, string secretIdentity)
{
Name = name;
this.secretIdentity = secretIdentity;
Mana = 100; // Начальная мана
}
}


// Вспомогательный класс для расчета урона, доступен только внутри файла
file class DamageCalculator
{
public int CalculateDamage(int baseDamage, int mana)
{
return baseDamage + (mana / 10);
}
}

Проблемы при неправильном использовании модификаторов доступа:

  1. public:Проблема: Если сделать все методы и свойства публичными, это может привести к нарушению инкапсуляции и повышению риска изменения важных данных извне.
    Пример: Если бы свойство Mana было публичным, другой класс мог бы изменить его значение напрямую, что нарушило бы логику игры.
  2. protected:Проблема: Если использовать protected для методов, которые не предназначены для переопределения или доступа в подклассах, это может запутать разработчиков и привести к ошибкам.
    Пример: Если бы метод PrepareSpell был защищенным, его могли бы вызывать подклассы, что может нарушить последовательность действий мага.
  3. internal:Проблема: Использование internal для методов или свойств, которые могут понадобиться в других сборках, ограничивает возможности расширения и повторного использования кода.
    Пример: Если бы метод CastSpell был внутренним, его невозможно было бы использовать в других сборках или модулях игры.
  4. private:Проблема: Использование private для методов или свойств, которые должны быть доступны другим классам или подклассам, может привести к избыточному коду и необходимости создавать методы доступа.
    Пример: Если бы свойство Name было приватным, необходимо было бы создавать публичные методы для доступа к нему, что усложнило бы код.
  5. file:Проблема: Если использовать file для классов, которые могут понадобиться в других файлах, это ограничивает гибкость и повторное использование кода.
    Пример: Если бы класс DamageCalculator понадобился в других файлах, пришлось бы дублировать код или перемещать его в общий доступ.

Использование всех модификаторов доступа помогает создать сбалансированный и безопасный код, который легко поддерживать и расширять.