что такое инкапсуляция в си шарп

Основы объектно-ориентированного программирования

Все основанные на объектах языки (C#, Java, С++, Smalltalk, Visual Basic и т.п.) должны отвечать трем основным принципам объектно-ориентированного программирования (ООП), которые перечислены ниже:

Инкапсуляция

Как данный язык скрывает детали внутренней реализации объектов и предохраняет целостность данных?

Наследование

Как данный язык стимулирует многократное использование кода?

Полиморфизм

Как данный язык позволяет трактовать связанные объекты сходным образом?

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

Роль инкапсуляции

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

Т.е. инкапсуляция представляет собой способности языка скрывать излишние детали реализации от пользователя объекта. Например, предположим, что используется класс по имени DatabaseReader, который имеет два главных метода: Open() и Close().

Фиктивный класс DatabaseReader инкапсулирует внутренние детали нахождения, загрузки, манипуляций и закрытия файла данных. Программистам нравится инкапсуляция, поскольку этот принцип ООП упрощает кодирование. Нет необходимости беспокоиться о многочисленных строках кода, которые работают «за кулисами», чтобы реализовать функционирование класса DatabaseReader. Все, что потребуется — это создать экземпляр и отправлять ему соответствующие сообщения (например, «открыть файл по имени AutoLot.mdf, расположенный на диске С:»).

С идеей инкапсуляции программной логики тесно связана идея защиты данных. В идеале данные состояния объекта должны быть специфицированы с использованием ключевого слова private (или, возможно, protected). Таким образом, внешний мир должен вежливо попросить, если захочет изменить или получить лежащее в основе значение. Это хороший принцип, поскольку общедоступные элементы данных можно легко повредить (даже нечаянно, а не преднамеренно).

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

Код и данные, составляющие вместе класс, называют членами. Данные, определяемые классом, называют полями, или переменными экземпляра. А код, оперирующий данными, содержится в функциях-членах, самым типичным представителем которых является метод. В C# метод служит в качестве аналога подпрограммы. (К числу других функций-членов относятся свойства, события и конструкторы.) Таким образом, методы класса содержат код, воздействующий на поля, определяемые этим классом.

Роль наследования

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

что такое инкапсуляция в си шарп. Смотреть фото что такое инкапсуляция в си шарп. Смотреть картинку что такое инкапсуляция в си шарп. Картинка про что такое инкапсуляция в си шарп. Фото что такое инкапсуляция в си шарп

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

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

Роль полиморфизма

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

По сути, — это член базового класса, определяющий реализацию по умолчанию, которая может быть изменена (или, говоря более формально, переопределена) в производном классе. В отличие от него, — это член базового класса, который не предусматривает реализации по умолчанию, а предлагает только сигнатуру. Когда класс наследуется от базового класса, определяющего абстрактный метод, этот метод обязательно должен быть переопределен в производном классе. В любом случае, когда производные классы переопределяют члены, определенные в базовом классе, они по существу переопределяют свою реакцию на один и тот же запрос.

Рассмотрим для примера стек, т.е. область памяти, функционирующую по принципу «последним пришел — первым обслужен». Допустим, что в программе требуются три разных типа стеков: один — для целых значений, другой — для значений с плавающей точкой, третий — для символьных значений. В данном примере алгоритм, реализующий все эти стеки, остается неизменным, несмотря на то, что в них сохраняются разнотипные данные. В языке, не являющемся объектно-ориентированным, для этой цели пришлось бы создать три разных набора стековых подпрограмм с разными именами. Но благодаря полиморфизму для реализации всех трех типов стеков в C# достаточно создать лишь один общий набор подпрограмм. Зная, как пользоваться одним стеком, вы сумеете воспользоваться и остальными.

В более общем смысле понятие полиморфизма нередко выражается следующим образом: «один интерфейс — множество методов«. Это означает, что для группы взаимосвязанных действий можно разработать общий интерфейс. Полиморфизм помогает упростить программу, позволяя использовать один и тот же интерфейс для описания общего класса действий. Выбрать конкретное действие (т.е. метод) в каждом отдельном случае — это задача компилятора. Программисту не нужно делать это самому. Ему достаточно запомнить и правильно использовать общий интерфейс.

Источник

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

Спецификатор общего доступа

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

Следующий пример иллюстрирует это:

Когда приведенный выше код компилируется и выполняется, он производит следующий результат:

Функция участника Display () и GetArea () также может напрямую обращаться к этим переменным без использования какого-либо экземпляра класса.

Спецификатор частного доступа

Спецификатор частного доступа позволяет классу скрыть свои переменные-члены и функции-члены от других функций и объектов. Только функции одного класса могут обращаться к своим частным членам. Даже экземпляр класса не может получить доступ к своим частным членам.

Следующий пример иллюстрирует это:

Когда приведенный выше код компилируется и выполняется, он производит следующий результат:

Защищенный спецификатор доступа

Защищенный спецификатор доступа позволяет дочернему классу обращаться к переменным-членам и функциям-членам его базового класса. Таким образом, это помогает в реализации наследования. Мы обсудим это более подробно в главе наследования.

Внутренний спецификатор доступа

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

Следующая программа иллюстрирует это:

Когда приведенный выше код компилируется и выполняется, он производит следующий результат:

В предыдущем примере обратите внимание, что функция-член GetArea ()не объявлена ​​с помощью любого спецификатора доступа. Тогда какой будет спецификатор доступа по умолчанию для члена класса, если мы не будем упоминать о нем?

Защищенный спецификатор внутреннего доступа

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

Источник

Инкапсуляция в Си++ и Си

что такое инкапсуляция в си шарп. Смотреть фото что такое инкапсуляция в си шарп. Смотреть картинку что такое инкапсуляция в си шарп. Картинка про что такое инкапсуляция в си шарп. Фото что такое инкапсуляция в си шарп

Определение

Инкапсуляция это набор инструментов для управления доступом к данным или методам которые управляют этими данными. С детальным определением термина “инкапсуляция” можно ознакомиться в моей предыдущей публикации на Хабре по этой ссылке. Эта статья сфокусирована на примерах инкапсуляции в Си++ и Си.

Инкапсуляция в Си++

По умолчанию, в классе ( class ) данные и методы приватные ( private ); они могут быть прочитаны и изменены только классом к которому принадлежат. Уровень доступа может быть изменен при помощи соответствующих ключевых слов которые предоставляет Си++.

В Си++ доступно несколько спецификаторов, и они изменяют доступ к данным следующим образом:

Для краткости, только два уровня (приватный и публичный) будут освещены в примерах.

Пример инкапсуляции

Попытка напечатать или изменить приватную переменную mobile_number из основной программы ( main ) вызовет ошибку при компиляции потому как доступ к приватным данным в классе ограничен.

Нарушение инкапсуляции с Друзьями (Хорошая практика)

В Си++ присутствует ключевое слово “друг” ( friend ) которое позволяет добавить исключения в общие правила доступа к данным. Если функция или класс названы другом ( friend ) класса Contact — они получают свободный доступ к защищенным или приватным данным.

Существует два основных правила дружбы — дружба не наследуется и не взаимна. Также, наличие “друзей” не изменяет уровень защищенности данных — приватные данные остаются приватными с исключением в виде “друга”.

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

Нарушение инкапсуляции с Преобразованием типов и Указателями (Плохая практика)

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

Си++ получил в наследство от Си множество инструментов, один из которых — преобразование типов ( typecasting ). По умолчанию, все переменные и методы в классе приватные. В то же время, стандартный уровень доступа к данным в структуре ( struct ) — публичный. Возможно создать структуру или полностью публичный класс в котором данные будут расположены идентично данным в классе Contact и используя преобразование типов получить доступ к приватным данным.

Приватные данные были прочитаны и изменены благодаря преобразованию типов

Инкапсуляция в Си

Традиционно считается что инкапсуляция — один из ключевых ООП принципов. Тем не менее, это не лимитирует использование этого принципа в процедурно-ориентированных языках. В Си, инкапсуляция используется давно, невзирая на отсутствие ключевых слов “приватный” и “публичный”.

Приватные переменные

В данном примере, структура была определена в отдельном исходном файле “private_var.c”. Поскольку инициализация структуры в Си требует выделения и освобождения памяти, несколько вспомогательных функций были добавлены.

В соответствующем заголовочном файле «private_var.h», структура Contact была объявлена, но ее содержание осталось скрытым для основной программы.

Таким образом, для “main.c” содержание структуры неизвестно и попытки прочитать или изменить приватные данные вызовут ошибку при компиляции.

Получение доступа к приватным переменным с Указателями

Преобразование типов может быть использовано для преодоления инкапсуляции в Си также как и в Си++, но данный подход уже был описан. Зная, что в структуре данные расположены в порядке их декларации, указатели и арифметика указателей подойдет для достижения цели.

Доступ к переменным в структуре ограничен. Тем не менее, спрятаны только переменные, не память в которой хранятся данные. Указатели можно рассматривать как ссылку на адрес памяти, и если эта память доступна программе — данные сохраненные в этой памяти можно прочитать и изменить. Если указатель назначен на память в которой структура хранит свои данные — их можно прочитать. Используя то же определение структуры (те же “.c” и “.h” файлы) и модифицированный “main.c” файл, ограничение доступа было преодолено.

Данные в структуре были прочитаны и модифицированы

Приватные функции

Функции, будучи внешними ( extern ) по умолчанию, видимы во всей так называемой единице трансляции ( translation unit ). Другими словами, если несколько файлов скомпилированы вместе в один объектный файл, любой из этих файлов сможет получить доступ к любой функции из любого другого файла. Использование ключевого слова “статический” ( static ) при создании функции ограничит ее видимость до файла в котором она была определена.Следовательно, для обеспечения приватности функции необходимо выполнить несколько шагов:

В соответствующем заголовочном файле «private_funct.h», print_numbers() была декларирована как статическая функция.

Получение доступа к приватным функциям

Вызвать функцию print_numbers() из основной программы возможно. Для этого можно использовать ключевое слово goto или передавать в main указатель на приватную функцию. Оба способа требуют изменений либо в исходном файле “private_funct.c”, либо непосредственно в теле самой функции. Поскольку эти методы не обходят инкапсуляцию а отменяют её, они выходят за рамки этой статьи.

Заключение

Инкапсуляция существует за пределами ООП языков. Современные ООП языки делают использование инкапсуляции удобным и естественным. Существует множество способов обойти инкапсуляцию и избежание сомнительных практик поможет ее сохранить как в Си, так и в Си++.

Источник

Классы и объекты C#: инкапсуляция

С наследованием в C# мы разобрались и можно переходить к следующему «киту» объектно-ориентированного программирования — инкапсуляции. Инкапсуляция — это возможность (механизм) с помощью которой мы можем спрятать от конечного пользователя реализацию того или иного метода, устройства объекта и так далее и представить в пользование только то, что необходимо для работы, обеспечив тем самым целостность объекта. Опять же, определение может быть немного трудным для понимания, поэтому разберемся с ним подробнее и на примерах.

Пример инкапсуляции

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

Как обеспечивается инкапсуляция в C#

В C# для инкапсуляции используются публичные ( public ) свойства и методы объекта, а переменные (за очень редким исключением) остаются закрытыми ( private ) от пользователя. Про уровни доступа мы говорили вот в этой статье.

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

Итого

Инкапсуляция в ООП позволяет скрыть от конечного пользователя реализацию той или иной части объекта (класса), обеспечивая тем самым целостность работы. Инкапсуляция в C# реализуется с использованием различных модификаторов доступа к полям и свойствам объектов. Без инкапсуляции нам бы пришлось перед использованием того или иного метода или свойства вникать в реализацию, чтобы не натыкаться на различного рода ограничения и ошибки, с инкапсуляцией же мы в большей степени уверены в том, что внутренние механизмы объекта максимально «разрулят» все возможные проблемы и, в случае необходимости, сообщат нам об исключительной ситуации.

Источник

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

Пролог: internal is new public

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

что такое инкапсуляция в си шарп. Смотреть фото что такое инкапсуляция в си шарп. Смотреть картинку что такое инкапсуляция в си шарп. Картинка про что такое инкапсуляция в си шарп. Фото что такое инкапсуляция в си шарп

Случился такой проект и в моей жизни. Очередной. Причём делаю я его под добровольным надзором, где за каждой моей строчкой следят. Соответственно, уже не только хотелось, но и надо было делать всё правильно. Одним из «правильно» было «чти инкапсуляцию и закрывайся по максимуму, потому что открыться всегда успеешь, а закрыться обратно потом будет поздно». И поэтому я везде, где только мог, стал использовать для классов модификатор доступа 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. И я пока понятия не имею, что это такое, и с чем его едят. Так как не сталкивался на практике. Но буду рад узнать в комментариях. Но не копипаст из документации, а реальные случаи, когда этот модификатор доступа может понадобится.

Источник

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

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