popov . dev

Main

Library

Articles

Модификаторы дос...

Модификаторы доступа C#

Все типы и типы членов в C# имеют уровень доступности. Можно ли их использовать из другого кода в текущей сборке или других сборках, зависит от уровня доступности. В C# существуют различные ключевые слова, называемые Модификаторами доступа, которые используются для определения этого уровня доступности. Они используются для указания области доступности элемента или типа.

В данной статье, мы расскажем о каждом модификаторе доступа, доступном в C#, их назначении и разъясним, как различные модификаторы доступа управляют тем, где и как можно получить доступ к членам класса, обеспечивая организацию и безопасность вашего кода.

Зачем нужны модификаторы доступа?

Модификаторы доступа используются в C# для управления тем, кто может видеть и использовать различные части вашего кода. Они помогают вам организовать и защитить ваш код, улучшая его удобство сопровождения.

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

Помечая некоторые методы и переменные как общедоступные, вы даете понять, какие части вашего кода предназначены для использования другими частями вашей программы или другими программистами.

Защитите свой код: сохраняйте важные части закрытыми.

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

Инкапсуляция: скрывайте детали

Вы можете скрыть сложные части вашего кода внутри класса, предоставляя только то, что необходимо. Это упрощает использование вашего кода и снижает вероятность ошибок.

Улучшение технического обслуживания: проще разобраться в коде как вам, так и другим программистам.

Когда другие программисты видят ваш код, модификаторы доступа помогают им понять, как его предполагается использовать. Они могут сразу увидеть, какие части безопасны для использования, а какие следует оставить в покое.

Что такое модификаторы доступа?

Как я упоминал выше, модификаторы доступа определяют уровень доступности элемента класса (метода, переменной и т.д.) из других частей программы. Они не разрешены для пространств имен. Пространства имен не имеют ограничений доступа.

В C# существует 5 модификаторов доступа:

  • public
  • private
  • protected
  • internal
  • file (только в C# 11 и поздних версиях)
Для элемента или типа разрешен только один модификатор доступа, за исключением случаев, когда вы используете комбинации protected internal или private protected.

С помощью модификаторов доступа можно задать следующие 7 уровней доступности:

  • public
  • private
  • protected
  • internal
  • internal protected
  • private protected
  • file

Теперь давайте дадим краткий обзор каждого уровня доступности с несколькими примерами.

Уровень доступности public

"Поделиться с миром". Элементы, помеченные как public, доступны из любого другого кода в той же сборке или другой сборке, которая ссылается на них. Это наименее ограничительный уровень доступа.

public class MyClass
{
    public int PublicField;

    public void PublicMethod() 
    {
        PublicField = 20;
    }
}

К PublicField и PublicMethod можно получить доступ из любой части вашей программы, даже из других классов или сборок. Это означает, что если другой класс создает экземпляр MyClass, он может напрямую обращаться к PublicField и вызывать PublicMethod.

Уровень доступности private

"Только для этого класса". Члены, помеченные как private, доступны только внутри того же класса или структуры. Они недоступны из-за пределов содержащего их класса.

public class MyClass
{
    private int privateField;

    private void PrivateMethod() 
    {
        privateField = 10;
    }
}

privateField и privateMethod доступны только внутри самого MyClass. Это означает, что вы не можете получить доступ к этим элементам из любого другого класса или даже производного класса. Только код внутри MyClass может считывать или изменять privateField или вызывать privateMethod.

Уровень доступности protected

"Совместное использование с производными классами". Элементы c уровнем protected доступны в пределах одного класса или из производных классов. Они недоступны из-за пределов класса или структуры.

public class MyClass
{
    protected int ProtectedField;

    protected void ProtectedMethod() 
    {
        ProtectedField = 30;
    }
}

public class DerivedClass : MyClass
{
    public void AccessProtectedMember() 
    {
        // Производный класс может получить доступ к элементам
        ProtectedMethod();
        ProtectedField = 40;
    }
}

ProtectedField и protectedMethod доступны в MyClass и любом классе, который наследуется от MyClass (например, DerivedClass). Это полезно для того, чтобы разрешить подклассам использовать определенные элементы их родительского класса.

Уровень доступности internal

"Внутри сборки". Элементы internal доступны только в пределах одной сборки. К ним нельзя получить доступ извне сборки, даже из производных типов.

public class MyClass
{
    internal int InternalField;

    internal void InternalMethod() 
    {
        InternalField = 50;
    }
}

Уровень доступности protected internal

"Обмен информацией между друзьями". Элементы protected internal доступны из той же сборки или из производных классов в другой сборке. Это комбинация модификаторов доступа protected и internal.

public class MyClass
{
    protected internal int ProtectedInternalField;

    protected internal void ProtectedInternalMethod() 
    {
        // Доступ к защищенному внутреннему методу
        // можно получить внутри той же сборки
        // или из производных классов в другой сборке
        ProtectedInternalField = 60;
    }
}

Обратите внимание, что ProtectedInternalField и ProtectedInternalMethod могут быть доступны любому коду в пределах одной сборки, как и внутренние элементы. Кроме того, к ним могут быть доступны производные классы, даже если эти производные классы находятся в другой сборке. Это обеспечивает гибкий уровень доступа для участников, которые должны быть доступны в обоих сценариях.

Уровень доступности private protected

"В безопасном месте и рядом с родственниками". Модификатор private protected access - это один из уровней доступа, доступных в C#. Он сочетает в себе аспекты как закрытого, так и защищенного модификаторов и обеспечивает определенный уровень контроля доступа.

Члены, объявленные с модификатором private protected, доступны в пределах одного класса или в производных классах, но только в том случае, если эти производные классы находятся в одной сборке.

public class BaseClass
{
    private protected int PrivateProtectedField;

    private protected void PrivateProtectedMethod()
    {  
        Console.WriteLine("private protected метод в BaseClass");
    }
}

public class DerivedClass : BaseClass
{
    public void AccessPrivateProtectedMember()
    {
        // Может получить доступ PrivateProtectedField и PrivateProtectedMethod
        PrivateProtectedField = 10;
        PrivateProtectedMethod();
    }
}

// Этот класс в такой же сборке но не наследуемый из BaseClass
public class AnotherClass
{
    public void TryAccessing()
    {
        var baseObject = new BaseClass();
        
        // Нет доступа к PrivateProtectedField или PrivateProtectedMethod
        // baseObject.PrivateProtectedField = 20; // Ошибка
        // baseObject.PrivateProtectedMethod(); // Ошибка
    }
}

В примере BaseClass содержит поле PrivateProtectedField и метод PrivateProtectedMethod, помеченные как private protected. Эти элементы доступны только внутри базового класса или производных классов, таких как DerivedClass, в той же сборке. Однако другой класс не может быть доступен, даже если он находится в той же сборке, поскольку он не является производным от BaseClass.

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

Уровень доступа file

"Секреты хранящиеся в одном файле". В C# 11 и более поздних версиях был введен новый модификатор доступа под названием file. Этот модификатор позволяет ограничить видимость типов файлом, в котором они объявлены. Это особенно полезно для сокрытия деталей реализации, которые не предназначены для использования за пределами конкретного исходного файла.

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

file class FilePrivateClass
{
    public void FilePrivateMethod()
    {
        Console.WriteLine("Этот метод из FilePrivateClass.");
    }
}

public class PublicClass
{
    public void PublicMethod()
    {
        // Есть доступ к FilePrivateClass потому что это другой файл
        FilePrivateClass filePrivate = new FilePrivateClass();
        filePrivate.FilePrivateMethod();
    }
}

Обратите внимание, что FilePrivateClass объявлен с модификатором file. Это означает, что доступ к нему возможен только в пределах того же файла, в котором он определен. Этот класс и его члены полностью скрыты от других файлов в том же проекте. PublicClass может создавать экземпляр FilePrivateClass и вызывать его методы, поскольку он находится в том же файле. Если вы попытаетесь получить доступ к FilePrivateClass из другого файла, он не будет виден, и вы получите сообщение об ошибке компиляции.

Модификатор доступа file полезен в сценариях, когда вы хотите сохранить некоторые детали реализации в тайне от конкретного файла. Это может помочь в:

  • Сокращение области применения типов и предотвращение их неправильного использования в других частях кодовой базы. Это означает, что вам меньше нужны вложенные типы, если вы хотите сохранить определенные типы в отдельном файле.
  • Организуйте код, сохраняя вспомогательные классы и методы в том же файле, что и основной класс, который они поддерживают.

По умолчанию

В C#, когда вы не указываете модификатор доступа, уровни доступа по умолчанию применяются в зависимости от типа элемента.

Ниже приведены уровни доступа по умолчанию для различных типов участников:

  • Классы и структуры верхнего уровня (не вложенные): по умолчанию используется значение internal.
  • Члены класса или структуры (поля, методы, свойства и т.д.): по умолчанию используется значение private.
  • Вложенные типы (классы, структуры, перечисления и т.д.): по умолчанию используется значение private.
  • Интерфейсы: как и классы и структуры, интерфейсы по умолчанию имеют доступ internal. Но члены интерфейса по умолчанию public, поскольку цель интерфейса - предоставить другим типам доступ к классу или структуре.
  • Перечисления: у финализаторов не может быть модификаторов доступности. Элементы типа enum всегда public, и никакие модификаторы доступа не могут быть применены.
  • Тип делегата, объявленный непосредственно в пространстве имен, по умолчанию имеет доступ internal.
// По умолчанию для глобального класса internal
class MyClass
{
    // Для полей, методов и свойств private
    int myField; 

    void MyMethod() 
    {
        // Реализация метода...
    }

    // Вложенные классы private
    class NestedClass 
    {
        // Элементы класса NestedClass...
    }
}

// Интерфейсы public
interface IMyInterface 
{
    void MyMethod();
}

// У перечислений public
enum MyEnum
{
    MyEnumMember
}

// Доступ делегатов по умолчанию internal
delegate int MyDelegate();

Видимость internal

Вы можете разрешить другим сборкам получать доступ к вашим internal типам, используя атрибут InternalsVisibleToAttribute. Это полезно для модульного тестирования, когда вы хотите протестировать внутренние элементы, не делая их public.

Атрибут InternalsVisibleTo добавляется в файл AssemblyInfo.cs или непосредственно в атрибуты сборки в вашем коде.

Допустим, у вас есть две сборки: MainAssembly и TestAssembly. Вы хотите, чтобы TestAssembly имел доступ к внутренним элементам MainAssembly.

В MainAssembly откройте файл AssemblyInfo.cs (обычно он находится в папке свойств) и добавьте следующие строки:

using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("TestAssembly")]

Поскольку TestAssembly теперь указан в атрибуте InternalsVisibleTo, он может получать доступ к внутренним элементам MainAssembly.

Некоторые ключевые моменты

  • Члены class или struct (включая вложенные классы и структуры-конструкторы) могут быть объявлены с любым из шести типов уровня доступа (кроме file).
  • Члены структуры не могут быть объявлены как protected, protected internal или private protected, поскольку struct не поддерживают наследование.
  • Производные классы не могут обладать большей доступностью, чем их базовые типы. Вы не можете объявить общедоступный класс B, который является производным от внутреннего класса A. Если бы это было разрешено, это привело бы к созданию public class, поскольку все protected или internal члены A доступны из производного класса.
  • Не все модификаторы доступа применимы ко всем типам или членам во всех контекстах. В некоторых случаях доступность содержащего типа ограничивает доступность его членов.
  • Когда в одном объявлении класса partialclass или метода partialclass не указывается его доступность, он имеет доступ к другому объявлению. Компилятор выдает ошибку, если в нескольких объявлениях для класса partialclass или метода partialclass объявляются разные возможности доступности.
  • Модификатор record для типа заставляет компилятор синтезировать дополнительные элементы. Модификатор record не влияет на доступность по умолчанию ни для record class, ни для record struct.
  • Элемент interface с доступом private должен иметь реализацию по умолчанию.

Заключение

Подводя итог, можно сказать, что к public элементам можно получить доступ из любого места, private элементы ограничены определяющим классом, file элементы являются private для определенного файла, protected элементы доступны для производных классов, internal элементы доступны в пределах одной сборки, protected internal элементы доступны в пределах одной сборки или производными классами, а private protected элементы доступны в пределах того же класса или в производных классах, которые находятся в той же сборке.

Теперь вы видите, как различные модификаторы доступа управляют доступностью полей и методов внутри класса.

Вот несколько рекомендаций в качестве последнего слова:

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

При разработке классов для наследования рассмотрите возможность использования элементов protected, чтобы позволить производным классам получать доступ к определенным элементам, сохраняя при этом инкапсуляцию.

Инкапсулируйте элементы данных, используя модификаторы доступа private, и предоставляйте их с помощью public свойств или методов. Это помогает поддерживать целостность данных и контролировать доступ к ним.

Если у вас есть элементы, которые должны быть доступны только в пределах одной сборки, используйте модификатор доступа internal. Это предотвращает непреднамеренный доступ извне сборки.

Comments

In order to leave your opinion, you need to register on the website