protected internal означает что

Уровни доступности (Справочник по C#)

Объявленная доступностьЗначение
publicНеограниченный доступ.
protectedДоступ ограничен содержащим классом или типами, которые являются производными от содержащего класса.
internalДоступ ограничен текущей сборкой.
protected internalДоступ ограничен текущей сборкой или типами, которые являются производными от содержащего класса.
privateДоступ ограничен содержащим типом.
private protectedДоступ ограничен содержащим классом или типами, которые являются производными от содержащего класса в текущей сборке. Доступно с версии C# 7.2.

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

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

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

Члены типаУровень доступности членов по умолчаниюДопустимые объявленные уровни доступности члена
enumpublicNone
classprivatepublic

private protected

interfacepublicpublic

private protected

structprivatepublic

* Элемент interface с доступностью типа private должен иметь реализацию по умолчанию.

Доступность вложенного типа зависит от домена доступности, который определяется объявленным уровнем доступности члена и доменом доступности непосредственно вмещающего его типа. Однако домен доступности вложенного типа не может выходить за границы домена доступности содержащего его типа.

Спецификация языка C#

Дополнительные сведения см. в спецификации языка C#. Спецификация языка является предписывающим источником информации о синтаксисе и использовании языка C#.

Источник

ООП. Часть 3. Модификаторы доступа, инкапсуляция

Классы, методы и поля не всегда могут постоять за себя. Рассказываем, как быть защитником в объектно-ориентированном программировании.

protected internal означает что. Смотреть фото protected internal означает что. Смотреть картинку protected internal означает что. Картинка про protected internal означает что. Фото protected internal означает что

protected internal означает что. Смотреть фото protected internal означает что. Смотреть картинку protected internal означает что. Картинка про protected internal означает что. Фото protected internal означает что

Инкапсуляция (от лат. in capsule — в оболочке) — это заключение данных и функционала в оболочку. В объектно-ориентированном программировании в роли оболочки выступают классы: они не только собирают переменные и методы в одном месте, но и защищают их от вмешательства извне (сокрытие).

Важно! Инкапсуляция не является сокрытием. Сокрытие — это часть инкапсуляции.

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

Все статьи про ООП

protected internal означает что. Смотреть фото protected internal означает что. Смотреть картинку protected internal означает что. Картинка про protected internal означает что. Фото protected internal означает что

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

Модификатор доступа public

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

Рассмотрим на примере класса Item:

Объявив экземпляр этого класса, можно обращаться к любым его полям в любом месте программы, где доступен сам объект (речь о локальных и глобальных переменных).

Так как поля публичные, в консоли они отобразятся без каких-либо проблем:

protected internal означает что. Смотреть фото protected internal означает что. Смотреть картинку protected internal означает что. Картинка про protected internal означает что. Фото protected internal означает что

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

Из-за того, что поле публичное, оно изменится:

protected internal означает что. Смотреть фото protected internal означает что. Смотреть картинку protected internal означает что. Картинка про protected internal означает что. Фото protected internal означает что

Это плохо по нескольким причинам:

Разумеется, это не лучшее, что может случиться с приложением.

Модификатор доступа private

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

Теперь эти поля нельзя будет изменить нигде, кроме как в методах этого класса. Но и получить их значение извне тоже не получится, а попытка вывести приведёт к ошибке:

protected internal означает что. Смотреть фото protected internal означает что. Смотреть картинку protected internal означает что. Картинка про protected internal означает что. Фото protected internal означает что

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

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

К такой практике прибегают Java-разработчики, но в C# есть более элегантный способ — свойства.

Теперь, чтобы получить данные, нужно обратиться к свойству, а не к полю:

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

Обратите внимание, что можно просто написать set; или get; если не требуется дополнительная логика. Это сработает, если у поля и свойства одинаковые имена и если это примитивный тип (int, float, char, double и другие). Со ссылочными типами (объекты и строки) это не работает.

Также можно менять логику работы со значением:

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

То есть если запустить вот такой код:

protected internal означает что. Смотреть фото protected internal означает что. Смотреть картинку protected internal означает что. Картинка про protected internal означает что. Фото protected internal означает что

Также можно создавать свойства без поля:

Это свойство вернёт true, если цена выше 5000, и false, если ниже.

Ключевое слово private можно также применять и к методам. Это делает их доступными только внутри класса.

Также приватным можно сделать сам класс, если он находится внутри другого класса:

Модификатор доступа internal

Иногда нужно сделать компонент доступным только внутри одного файла — например, в Program.cs, Item.cs или любом другом. Для этого используется ключевое слово internal.

Класс Backpack можно будет использовать только внутри файла Program.cs, и попытка объявить его внутри другого файла приведёт к ошибке.

Ключевое слово static

Статичность относится не совсем к уровням доступа, но тоже помогает заключить реализацию функционала в оболочку класса. Статичность позволяет обращаться к методам или полям, не создавая объект.

Метод Sum () используется в классе Program, хотя экземпляр класса Calc не создавался. При этом можно сделать статичным как отдельный метод или свойство, так и весь класс. В этом случае все поля и методы тоже должны быть статичными.

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

Другой пример — класс Math. Его можно использовать, чтобы выполнять различные математические операции (получение квадратного корня, модуляция, получение синуса, косинуса и так далее). У него много методов, а также он хранит различные константы вроде числа пи.

Домашнее задание

Напишите класс GameObject, в котором будут храниться координаты объекта. Координаты должны быть доступны для чтения, а их изменение должно происходить в методе Move ().

Заключение

Есть и другие ключевые слова:

Они будут рассмотрены в статье о наследовании.

Большая часть курса «Профессия С#-разработчик» посвящена именно ООП —
не только теории, но и практике. Вы научитесь писать программы, подбирая нужные инструменты — от инкапсуляции до полиморфизма. К концу курса у вас будет портфолио из нескольких проектов, а также все знания и навыки, которые нужны для получения первой работы.

Источник

Модификаторы доступа (Руководство по программированию в C#)

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

Сводная таблица

Расположение вызывающего объектаpublicprotected internalprotectedinternalprivate protectedprivate
В классе✔️️✔️✔️✔️✔️✔️
Производный класс (та же сборка)✔️✔️✔️✔️✔️
Непроизводный класс (та же сборка)✔️✔️✔️
Производный класс (другая сборка)✔️✔️✔️
Непроизводный класс (другая сборка)✔️

В следующих примерах показано, как изменить модификаторы доступа для типа или члена типа:

Не все модификаторы доступа подходят для всех типов или членов во всех контекстах. В некоторых случаях доступность члена типа ограничивается доступностью содержащего его типа.

Доступность классов, записей и структур

Доступность членов классов, записей и структур

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

Методы завершения не могут иметь модификаторы доступа.

Другие типы

Спецификация языка C#

Дополнительные сведения см. в спецификации языка C#. Спецификация языка является предписывающим источником информации о синтаксисе и использовании языка C#.

Источник

Инкапсуляция для настоящих самураев, или нюансы, связанные с ключевым словом internal в C#

Пролог: internal is new public

Каждый из нас мечтал о проекте, где всё будет сделано правильно. Это кажется вполне естественным. Как только ты узнаёшь о самой возможности писать хороший код, как только слышишь легенды о том самом коде, который можно легко читать и изменять, сразу загораешься тем самым «ну вот теперь я точно всё сделаю правильно, я ведь теперь умный и Макконнела читал».

protected internal означает что. Смотреть фото protected internal означает что. Смотреть картинку protected internal означает что. Картинка про protected internal означает что. Фото protected internal означает что

Случился такой проект и в моей жизни. Очередной. Причём делаю я его под добровольным надзором, где за каждой моей строчкой следят. Соответственно, уже не только хотелось, но и надо было делать всё правильно. Одним из «правильно» было «чти инкапсуляцию и закрывайся по максимуму, потому что открыться всегда успеешь, а закрыться обратно потом будет поздно». И поэтому я везде, где только мог, стал использовать для классов модификатор доступа internal вместо public. И, естественно, когда ты начинаешь активно использовать новую для тебя фичу языка, возникают некоторые нюансы. О них по порядку и хочу рассказать.

Исключительно для того, чтобы напомнить и обозначить.

Юнит-тесты и дружественные сборки

В C++ была такая странноватая фича, как friendly classes. Классы можно было назначить друзьями, и тогда граница инкапсуляции между ними стиралась. Подозреваю, что это не самая странная фича в C++. Возможно, даже в десятку самых странных не входит. Но выстрелить себе в ногу, связав несколько классов намертво, как-то слишком уж легко, а подходящий случай под эту фичу придумать очень тяжело.

А потом в том же проекте я начал познавать одну из ветвей пути настоящего самурая: юнит-тестирование. А по фэн-шую юнит-тесты должны лежать в отдельной сборке. По тому же фэн-шую всё, что можно спрятать внутри сборки, нужно спрятать внутри сборки. Я встал перед весьма и весьма неприятным выбором. Или тесты будут лежать рядышком и уходить клиенту вместе с полезным для него кодом, или всё покроется ключевым словом public, как долго лежавший в сырости хлебушек.

И вот тут откуда-то из закромов моей памяти было добыто что-то про дружественные сборки. Оказалось, что если у вас есть сборка «YourAssemblyName», то можно написать вот так:

И сборка «YourAssemblyName.Tests» будет видеть то, что помечено ключевым словом internal в «YourAssemblyName». Строчку эту можно вписать, чуть что, в AssemblyInfo.cs, который VS создаёт специально для хранения таких атрибутов.

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

Чуть не забыл один важный момент. Действия атрибута InternalsVisibleTo одностороннее.

protected protected. Чтобы понять суть претензий компилятора, давайте вспомним, какие ограничения накладывают internal и protected. internal — только внутри сборки. protected — только наследники. Заметьте, любые наследники. А если класс B пометить как public, то в другой сборке можно определить его наследников. И тогда акссесор set действительно получит доступ туда, куда его не имеет всё свойство. Так как компилятор C# параноидален, он даже возможности такой допустить не может.

Спасибо ему за это, но нам нужно дать наследникам доступ к аксессору. И специально для таких случаев есть модификатор доступа protected internal.

Так что если мы хотим, чтобы компилятор позволил нам пользоваться этим свойством и задавать его в наследниках, нужно сделать так:

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

Интерфейсы

Итак, ситуация: A, I, B сидели на трубе.

Сидели ровно и за пределы сборки не совались. Но были забракованы компилятором. Тут суть претензий ясна из сообщения об ошибке. Реализация интерфейса должна быть открытой. Даже если сам интерфейс закрыт. Было бы логично привязать доступ реализации интерфейса к его доступности, но чего нет, того нет. Реализация интерфейса должна быть public.

Обратите внимание, что во втором случае нет модификатора доступа. Кому в таком случае доступна реализация метода? Скажем так, никому. Проще показать на примере:

Явная реализация интерфейса I означает, что пока мы явно не приведём переменную к типу I, методов реализующий этот интерфейс не существует. Каждый раз писать (b as I).SomeMethod() может быть излишней нагрузкой. Как и ((I)b).SomeMethod(). И я нашёл два способа это дело обойти. До одного додумался сам, а второй честно нагуглил.

Способ первый — фабрика:

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

Способ второй — методы расширения:

Что удивительно, это срабатывает. Эти строки перестают выдавать ошибку:

Ведь обращение идёт, как нам подсказывает IntelliSense в Visual Studio, не к методам явной реализации интерфейса, а к методам расширения. А к ним обращаться никто не запрещает. И методы расширения интерфейса можно вызывать на всех его реализациях.

Но остаётся один нюанс. Внутри самого класса нужно обращаться к этому методу через ключевое слово this, иначе компилятор не поймёт, что мы хотим обратиться к методу расширения:

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

Рефлексия

Я об это больно стукнулся, когда попытался найти через рефлексию конструктор, который, естественно, был помечен, как internal, у internal-класса. И оказалось, что рефлексия не выдаст ничего, что не было бы public. И это, в принципе, логично.

Во-первых, рефлексия, если я правильно помню то, что писали умные люди в умных книгах, это про поиск информации в метаданных сборки. Которые, по идее, не должны выдавать лишнего (я так думал, по крайней мере). Во-вторых, основное применение рефлексии — сделать вашу программу расширяемой. Вы предоставляете посторонним какой-то интерфейс (возможно, даже в виде интерфейсов, фить-ха!). А они его реализуют и предоставляют плагины, моды, расширения в виде загружаемой на ходу сборки, из которой рефлексия их и достаёт. И само собой, ваше API будет public. То есть, смотреть на internal через рефлексию невозможно технически и бессмысленно с практической точки зрения.

Update. Тут в комментариях выяснилось, что рефлексия позволяет, если её явно попросить об этом, отрефлексировать вообще всё. Будь оно хоть internal, хоть private. Если вы не пишете какой-то инструмент для анализа кода, старайтесь так не делать, пожалуйста. Текст дальше всё ещё актуален для случаев, когда мы ищем открытые типы членов. И вообще, не проходите мимо комментариев, там много чего интересного.

На этом можно было бы и закончить с рефлексией, но давайте вернёмся к предыдущему примеру, где A, I, B сидели на трубе:

Автор класса A решил, что ничего страшного не случится, если метод internal-класса пометить как public, чтобы компилятор не ныл, и чтобы не пришлось городить ещё кода. Интерфейс отмечен, как internal, класс, его реализующий, отмечен как internal, снаружи до метода, помеченного как public, вроде бы никак не добраться.

И тут открывает дверь и тихонько крадётся рефлексия:

Изучите этот код, вбейте его в студию, если вам так хочется. Тут мы пытаемся с помощью рефлексии найти все методы из всех типов нашей трубы (namespace Pipe). И вот какие результаты нам это даёт:

In type I we found Void SomeMethod()
NULL! Can’t find method SomeMethod in type IExtensions
In type A we found Void SomeMethod()
NULL! Can’t find method OtherMethod in type A
NULL! Can’t find method SomeMethod in type B
NULL! Can’t find method OtherMethod in type B

Сразу скажу, что используя объект типа MethodInfo, найденный метод можно вызвать. То есть, если рефлексия что-то нашла, то нарушить инкапсуляцию чисто теоретически можно. И у нас кое-что найдено. Во-первых, тот самый public void SomeMethod() из класса A. Это было ожидаемо, что тут ещё сказать. У этой поблажки всё-таки могут быть последствия. Во-вторых, void SomeMethod() из интерфейса I. Это уже интереснее. Как бы мы не запирались, но абстрактные методы, размещённые в интерфейсе (или что на самом деле там размещает CLR) на самом деле являются открытыми. Отсюда вывод, вынесенный в отдельный абзац:

Смотрите внимательно кому и какие объекты типа System.Type вы отдаёте.

Но тут ещё один нюанс с этими двумя найденными методами, который я хотел бы рассмотреть. Методы internal-интерфейсов и открытые методы internal-классов можно найти с помощью рефлексии. Как человек разумный, я сделаю вывод, что они попадают в метаданные. Как человек опытный, я этот вывод проверю. И в этом нам поможет ILDasm.

Сборка была собрана в режипрме Release

TypeDef #2 (02000003)
——————————————————-
TypDefName: Pipe.I (02000003)
Flags : [NotPublic] [AutoLayout] [Interface] [Abstract] [AnsiClass] (000000a0)
Extends : 01000000 [TypeRef]
Method #1 (06000004)
——————————————————-
MethodName: SomeMethod (06000004)
Flags : [Public] [Virtual] [HideBySig] [NewSlot] [Abstract] (000005c6)
RVA : 0x00000000
ImplFlags : [IL] [Managed] (00000000)
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
No arguments.

Беглый осмотр показывает, что в метаданные попадает всё, как бы оно ни было помечено. Рефлексия ещё заботливо от нас прячет то, что посторонним видеть не положено. Так что вполне может быть, что лишние пять строк кода на каждый метод internal-интерфейса не такое уж и большое зло. Тем не менее, главный вывод остаётся прежним:

Смотрите внимательно кому и какие объекты типа System.Type вы отдаёте.

Но это уже, конечно, следующий уровень, после воцарения ключевого слова internal во всех местах, где нет необходимости в public.

Знаете, что самое классное в использовании ключевого слова internal везде внутри сборки? Когда она разрастётся, вам придётся её поделить на две и больше. А в процессе вам придётся взять паузу на то, чтобы сделать некоторые типы открытыми. И вам придётся задуматься о том, какие именно типы достойны того, чтобы стать открытыми. Хотя бы мельком.

Это означает следующее: эта практика написания кода заставит вас ещё раз задуматься о том, какую форму примет архитектурная граница между новорожденными сборками. Что может прекраснее?

Начиная с версии C# 7.2 появился новый модификатор доступа private protected. И я пока понятия не имею, что это такое, и с чем его едят. Так как не сталкивался на практике. Но буду рад узнать в комментариях. Но не копипаст из документации, а реальные случаи, когда этот модификатор доступа может понадобится.

Источник

Введение в ООП с примерами на C#. Часть пятая. Всё о модификаторах доступа

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

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

Давайте в этот раз возьмём определение из Википедии (в русской Википедии статьи access modifiers нет, поэтому здесь приводим свой перевод — прим. перев.) :

Модификаторы доступа (или спецификаторы доступа) — ключевые слова в объектно-ориентированных языках, которые задают (внезапно!) параметры доступа для классов, методов и прочих элементов. Модификаторы доступа — специфичная часть языков программирования для облегчения инкапсуляции компонентов.

Модификаторы public, private, protected

Традиционно сразу переходим к практике. Давайте попробуем выполнить следующий код:

Результатом выполнения этого кода будет:

Теперь попробуем получить доступ к AAA() напрямую:

‘AccessModifiers.Modifiers.AAA()’ is inaccessible due to its protection level

Модификаторы доступа и наследование

Снова попробуем выполнить код:

Запускаем код и видим…

‘AccessModifiers.ModifiersBase.AAA()’ is inaccessible due to its protection level

Приватные члены недоступны даже дочерним классам. Публичные члены доступны всем, это понятно. Модификатор же protected по сути и обозначает, что член доступен только дочерним классам — вызов CCC() в примере выше не вызывает никаких ошибок.

Модификатор Internal для классов

Давайте рассмотрим следующий сценарий: мы создаём в новой библиотеке классов (назовём её AccessModifiersLibrary ) класс ClassA и помечаем его как internal :

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

Compile time error: ‘AccessModifiersLibrary.ClassA’ is inaccessible due to its protection level

Модификаторы для пространств имён

Давайте попробуем сделать с предыдущим кодом следующее:

Конечно, это не скомпилируется:

Compile time error: A namespace declaration cannot have modifiers or attributes

Приватные классы

Если мы попробуем скомпилировать код, приведённый выше, то получим ошибку:

Compile time error: Elements defined in a namespace cannot be explicitly declared as private, protected, or protected internal

Подробнее о модификаторах членов класса

Что будет, если мы захотим назначить члену класса больше одного модификатора доступа?

Будет ошибка компиляции:

Compile time error: More than one protection modifier

А как поведёт себя язык, если мы создадим public метод в internal классе?

Вывод после компиляции:

‘AccessModifiersLibrary.ClassA’ is inaccessible due to its protection level

The type ‘AccessModifiersLibrary.ClassA’ has no constructors defined

‘AccessModifiersLibrary.ClassA’ is inaccessible due to its protection level

‘AccessModifiersLibrary.ClassA’ does not contain a definition for ‘MethodClassA’ and
no extension method ‘MethodClassA’ accepting a first argument of type ‘AccessModifiersLibrary.ClassA’
could be found (are you missing a using directive or an assembly reference?)

Как много ошибок… Дело в том, что какими бы модификаторами не обладали члены internal класса, их всё равно нельзя вызвать оттуда, где не виден сам класс. А что будет, если мы попробуем сделать наоборот — вызвать private или internal метод у public класса?

‘AccessModifiersLibrary.ClassA’ does not contain a definition
for ‘MethodClassA’ and no extension method ‘MethodClassA’ accepting a first argument
of type ‘AccessModifiersLibrary.ClassA’ could be found (are you missing a using directive or an assembly reference?)

‘AccessModifiersLibrary.ClassA’ does not contain a definition for ‘MethodClassA’ and no extension
method ‘MethodClassA’ accepting a first argument of type ‘AccessModifiersLibrary.ClassA’ could be
found (are you missing a using directive or an assembly reference?)

Увы, так делать тоже нельзя.

Модификатор protected internal

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

Protected поля

Здесь всё будет немного сложнее. Давайте напишем следующий код:

Если мы его запустим, то получим ошибку:

Cannot access protected member ‘AccessModifiers.AAA.a’ via a qualifier of type ‘AccessModifiers.AAA’;
the qualifier must be of type ‘AccessModifiers.BBB’ (or derived from it)

(От редакции) Скорее всего, это сделано, чтобы нельзя было делать следующим образом:

Приоритет модификаторов

Compile time error: Inconsistent accessibility: base class ‘AccessModifiers.AAA’ is less accessible than class ‘AccessModifiers.BBB’

Inconsistent accessibility: return type ‘AccessModifiers.AAA’ is less accessible than method ‘AccessModifiers.BBB.MethodB()’

Inconsistent accessibility: field type ‘AccessModifiers.AAA’ is less accessible than field ‘AccessModifiers.BBB.aaa’

Подведём итоги:

Работу с константами и sealed классами (которая тоже осуществляется за счёт модификаторов доступа) мы разберём в следующей статье.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *