190
Глава.6 .Основные.сведения.о.членах.и.типах
Чтобы
сборка группы
Б
могла использовать типы группы
А
, группа
А
должна
определить все нужные второй группе типы как открытые. Однако это означает,
что эти типы будут доступны абсолютно всем сборкам. В результате разработчики
другой компании смогут написать код, использующий общедоступные типы, а это
нежелательно.
Вполне возможно, в полезных типах действуют определенные усло-
вия, которым должна соблюдать группа
Б
при написании кода, использующего типы
группы
А
. То есть нам необходим способ, который бы позволил группе
А
определить
свои
типы как внутренние, но в то же время предоставить группе
Б
доступ к этим
типам. Для таких ситуаций в CLR и C# предусмотрен механизм
дружественных
сборок
(friend assemblies). Кстати говоря, он пригодится еще и в ситуации со сбор-
кой, содержащей код, который выполняет модульные тесты с внутренними типами
другой сборки.
В процессе создания сборки можно указать другие сборки, которые она будет
считать «друзьями», — для этого служит атрибут
InternalsVisibleTo
, опреде-
ленный в пространстве имен
System.Runtime.CompilerServices
. У
атрибута есть
строковый параметр, определяющий имя дружественной сборки и ее открытый ключ
(передаваемая атрибуту строка не должна содержать информацию о версии, регио-
нальных стандартах или архитектуре процессора). Заметьте, что дружественные
сборки получают доступ
ко всем
внутренним типам сборки, а также к внутренним
членам этих типов. Приведем пример сборки, которая объявляет дружественными
две другие
сборки со строгими именами
Wintellect
и
Microsoft
:
using System;
using System.Runtime.CompilerServices; // Для атрибута InternalsVisibleTo
// Внутренние типы этой сборки доступны из кода двух следующих сборок
// (независимо от версии или региональных стандартов)
[assembly:InternalsVisibleTo("Wintellect, PublicKey=12345678...90abcdef")]
[assembly:InternalsVisibleTo("Microsoft, PublicKey=b77a5c56...1934e089")]
internal sealed class SomeInternalType { ... }
internal sealed class AnotherInternalType { ... }
Обратиться из дружественной сборки к внутренним типам представленной здесь
сборки очень просто. Например, дружественная сборка
Wintellect
с открытым клю-
чом
12345678…90abcdef
может обратиться к внутреннему типу
SomeInternalType
представленной сборки следующим образом:
using System;
internal sealed class Foo {
private static Object SomeMethod() {
// Эта сборка Wintellect получает доступ к внутреннему типу
// другой сборки, как если бы он был открытым
SomeInternalType sit = new SomeInternalType();
return sit;
}
}
191
Доступ.к.членам.типов
Поскольку внутренние члены принадлежащих сборке типов становятся до-
ступными для дружественных сборок, следует очень
осторожно подходить к опре-
делению уровня доступа, предоставляемого членам своего типа, и объявлению
дружественных сборок. Заметьте, что при компиляции дружественной (то есть не
содержащей атрибута
InternalsVisibleTo
) сборки компилятору C#
требуется за-
давать параметр
/out:
файл
. Он нужен компилятору, чтобы узнать имя компилиру-
емой сборки и определить, должна ли результирующая сборка быть дружественной.
Можно подумать, что компилятор C# в состоянии самостоятельно выяснить это
имя, так как он обычно самостоятельно определяет имя выходного файла; однако
компилятор «узнает» имя выходного файла только после завершения компиляции.
Поэтому требование указывать этот параметр позволяет
значительно повысить
производительность компиляции.
Аналогично, при компиляции модуля (в противоположность сборке) с параметром
/t:module
, который должен стать частью дружественной сборки, необходимо также
использовать параметр
/moduleassemblyname:
строка
компилятора C#. Последний
параметр говорит компилятору, к какой сборке будет относиться модуль, чтобы тот
разрешил коду этого модуля обращаться к внутренним типам другой сборки.
Do'stlaringiz bilan baham: