В C# есть возможность объявить «дружественную сборку». Если сборка Смит говорит, что сборка Джонс – её друг, то коду Джонса разрешается видеть «внутренние» типы Смита, как будто они публичные(*). Это довольно удобная возможность строить «семьи» сборок, которые разделяют общие детали реализации.

Компилятор требует выполнения одного достаточно интересного правила насчёт именования дружественных сборок. Если сборка Смит имеет строгое имя и объявляет сборку Джонс своим другом, то Джонс тоже должна иметь строгое имя. Однако, если у Смита нет строгого имени, то и Джонса необязательно строго именовать.

Меня иногда спрашивают: «с чего бы это?»

Когда вы вызываете метод Смита и передаёте в него некоторые данные, вы собственно доверяете Смиту в том, что он (1) будет правильно пользоваться этими данными; данные могут содержать важную информацию, которой Смит не должен злоупотреблять, и (2) разрешаете ему выполнять некоторые действия от вашего имени. За пределами комьютерного мира сущность, которой вы доверяете тайны и разрешаете действовать от вашего имени, называется «поверенный» (**). Это заставляет меня задуматься, что обычно свидетельствует о проблеме.

Вы хотите нанять поверенного. Вы идете в «Адвокаты Смит и Джонс», встречаетесь со Смитом, который выгладит как заслуживающий доверие человек слева на фотографии:

image

Сценарий 1:

Вы проверяете документы Смита. Это действительно Мэл Смит. Вы раздумываете, стоит ли доверить Смиту секрет, и разрешить ему действовать от вашего имени в отношении этого секрета. Смит говорит «я делюсь всеми своими секретами с моим партнёром Гриффом Рисом Джонсом, документы которого вы можете сейчас проверить, вот Джонс, вот его документы. Джонс также будет действовать от вашего имени. У него есть полный доступ ко всем секретам нашей организации».

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

(Обе сборки Смит и Джонс имеют строгие имена. То, есть, у них есть «документы», которые вы можете проверить. Внутренности Смита доступны Джонсу. Всё в порядке).

Сценарий 2:

Вы проверяете документы. Это Мэл Смит. Смит говорит «Кстати, я рассказываю свои секреты всем, кто называет себя Джонсом, я не парюсь с проверкой документов, а просто им верю, да и вам стоит так поступать! Все Джонсы – надёжные парни, включая моего партнёра Джонса. Старина Джонс! Нет, вы не можете посмотреть документы Джонзи. У этого Джонса вовсе нет документов».

Это смехотворно. Конечно же это разрывает «цепь взаимного доверия», которую вы строили, проверяя документы Смита в самом начале.

(Компилятор не даёт вам попасть в эту ужасную ситуацию, запрещая Смиту делать это; Смит, строго-именованная сборка, может объявить свои внутренние детали видимыми только для другой строго-именованной сборки. Смит не может показывать свои внутренности любой сборке с именем Джонс - нестрого-именованной сборке в этом сценарии. Мы запрещаем Смиту показывать внутренние детали сборкам без строгого имени, чтобы Смит не мог случайно создать такую дыру в безопасности, или нечаянно заставить вас поверить в то, что его внутренности спрятаны от частично-доверенного кода.)

Сценарий 3:

Вы не проверяете документы Смита. Фактически, вы раскрываете ваши тайны и даёте права поверенного любому Смиту, неважно кто он и откуда. Первый же Смит, встреченный на улице, говорит «кстати, я расскажу все свои секреты любому по фамилии Джонс».

Вас это беспокоит? Почему? Вы уже раскрываете свои секреты любому по фамилии Смит! Если жулику нужны ваши тайны, то он может притвориться Джонсом и получить их у Смита, или притвориться Смитом и получить их прямо от вас, но в обоих случаях проблема в том, что это вы раздаёте секреты и права поверенного случайным прохожим.

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

*****************

(*) Сборки с полным доверием, конечно же, всегда могут увидеть приватные и внутренние детали других сборок при помощи рефлексии; это и означает «полное доверие». И в новой модели безопасности CLR, две сборки с одинаковым набором разрешений могут видеть приватные и внутренние детали друг друга при помощи рефлексии. Но дружественные сборки – единственный механизм, предоставляющий поддержку подсматривания за внутренними деталями другой сборки во время компиляции.

(**) или «делегат», которого я не стал применять по той очевидной причине, что это означает кое-что техническое в С#.

оригинал статьи