Ссылочные сборки
Ссылочные сборки (reference assemblies) — особая разновидность сборок, которые содержат только минимальный объем метаданных, необходимый для представления общедоступного API-интерфейса библиотеки. Такие сборки включают в себя объявления для всех элементов, которые важны при указании ссылки на сборку в средствах сборки, но исключают все реализации элементов, а также объявления закрытых элементов, не имеющих наблюдаемого влияния на их контракт API. Обычные сборки, в отличие от них, называются сборками реализации.
Ссылочные сборки не могут быть загружены для выполнения, но они могут передаваться как входные данные компилятора так же, как сборки реализации. Ссылочные сборки обычно распределяются с помощью пакета средств разработки программного обеспечения (SDK) определенной платформы или библиотеки.
Использование ссылочных сборок позволяет разработчикам создавать программы, предназначенные для конкретной версии библиотеки, без наличия полной сборки реализации для этой версии. Допустим, на компьютере установлена только последняя версия определенной библиотеки, но требуется создать программу, предназначенную для более ранней версии этой библиотеки. При компиляции непосредственно из сборки реализации вы можете случайно использовать элементы API, которые недоступны в более ранней версии, и обнаружите эту ошибку только при проверке программы на целевом компьютере. При компиляции из ссылочной сборки для более ранней версии сразу же возникает ошибка времени компиляции.
Ссылочная сборка также может представлять контракт, то есть набор API-интерфейсов, который не соответствует конкретной сборке реализации. Такие ссылочные сборки, называемые сборками контракта, можно использовать для нескольких платформ, поддерживающих один и тот же набор API-интерфейсов. Например, .NET Standard включает сборку контракта, netstandard.dll, которая представляет набор общих API-интерфейсов, совместно используемых различными платформами .NET. Реализации этих API-интерфейсов содержатся в разных сборках на разных платформах, например mscorlib.dll в .NET Framework или System.Private.CoreLib.dll в .NET Core. Библиотека, нацеленная на .NET Standard, может выполняться на всех платформах, поддерживающих .NET Standard.
Использование ссылочных сборок
Чтобы использовать в проекте определенные API-интерфейсы, необходимо добавить ссылки на их сборки. Ссылки можно добавлять либо на сборки реализации, либо на ссылочные сборки. По возможности рекомендуется использовать ссылочные сборки если они доступны. Таким образом, вы будете гарантированно использовать в целевой версии только поддерживаемые члены API, которые были предназначены для этого разработчиками API. Применяя ссылочную сборку, вы гарантированно не будете зависеть от деталей реализации.
Ссылочные сборки для библиотек .NET Framework распределяются с помощью пакетов нацеливания. Их можно получить, скачав автономный установщик или выбрав компонент в Visual Studio Installer. См. дополнительные сведения об установке .NET Framework для разработчиков. Для .NET Core и .NET Standard ссылочные сборки автоматически скачиваются при необходимости (через NuGet) и ссылки на них добавляются автоматически. Для .NET Core 3.0 и более поздних версий ссылочные сборки для основной платформы находятся в пакете Microsoft.NETCore.App.Ref (до версии 3.0 использовался пакет Microsoft.NETCore.App).
При добавлении ссылок на сборки .NET Framework в Visual Studio с помощью диалогового окна Добавление ссылки вы выбираете сборку из списка, и Visual Studio автоматически находит ссылочные сборки, соответствующие требуемой версии .NET Framework, выбранной в проекте. То же самое применимо для добавления ссылок непосредственно в проект MSBuild с помощью элемента проекта Reference. Вам необходимо указать только имя сборки, а не полный путь к файлу. При добавлении ссылок на эти сборки в командной строке с помощью параметра компилятора -reference
(в C# и в Visual Basic) или с помощью метода Compilation.AddReferences в API Roslyn необходимо вручную указать файлы ссылочной сборки для правильной версии целевой платформы. Файлы ссылочной сборки .NET Framework находятся в каталоге %ProgramFiles(x86)%\Reference Assemblies\Microsoft\Framework\.NETFramework. Для .NET Core можно принудительно выполнить операцию публикации, чтобы скопировать ссылочные сборки для целевой платформы в подкаталог publish/refs выходного каталога, установив для свойства проекта PreserveCompilationContext
значение true
. Затем можно передать эти файлы ссылочной сборки компилятору. Для поиска их путей можно использовать DependencyContext
из пакета Microsoft.Extensions.DependencyModel.
Так как ссылочные сборки не содержат реализации, они не могут быть загружены для выполнения. Любые попытки сделать это приведут к возникновению исключения System.BadImageFormatException. Если вам нужно изучить содержимое ссылочной сборки, ее можно загрузить в контекст только для отражения в .NET Framework (с помощью метода Assembly.ReflectionOnlyLoad) или в MetadataLoadContext в .NET Core.
Создание ссылочных сборок
Рекомендуется создавать ссылочные сборки для библиотек в тех случаях, когда их пользователям требуется создавать программы на основе множества разных версий отдельной библиотеки. Распространение сборок реализации для всех этих версий может оказаться нецелесообразным из-за их большого размера. Ссылочные сборки имеют меньший размер, поэтому их распространение в составе пакета SDK для библиотеки уменьшает объем скачиваемых данных и экономит место на диске.
Интегрированные среды разработки и средства сборки также могут использовать ссылочные сборки, чтобы сократить время сборки в случае больших решений, состоящих из нескольких библиотек классов. Как правило, в сценариях инкрементной сборки проект перестраивается при изменении любого из его входных файлов, включая сборки, от которых он зависит. Сборка реализации изменяется каждый раз, когда программист изменяет реализацию любого элемента. Ссылочная сборка изменяется только при ее влиянии на общедоступный API. Таким образом, использование ссылочной сборки в качестве входного файла вместо сборки реализации позволяет в некоторых случаях пропустить сборку зависимого проекта.
Вы можете создавать ссылочные сборки:
- В проекте MSBuild с помощью свойства проекта
ProduceReferenceAssembly
. - При компиляции программы из командной строки, указывая параметры компилятора
-refonly
(C# / Visual Basic ) или-refout
(C# / Visual Basic). - При использовании API Roslyn путем установки для параметра EmitOptions.EmitMetadataOnly значения
true
, а для параметра EmitOptions.IncludePrivateMembers значенияfalse
в объекте, переданном в метод Compilation.Emit.
Если хотите распределить ссылочные сборки с помощью пакетов NuGet, их необходимо включить в подкаталог ref\ каталога пакета, а не в подкаталог lib\ , используемый для сборок реализации.
Структура ссылочных сборок
Ссылочные сборки являются расширением связанной концепции — сборок, содержащих только метаданные. Тела методов в сборках, состоящих только из метаданных, заменяются одним телом throw null
, но такие сборки включают все члены, кроме анонимных типов. Тело throw null
используется для того, чтобы могло выполняться средство PEVerify для проверки полноты метаданных, что было бы невозможно при отсутствии тела.
Ссылочные сборки удаляют метаданные (закрытые члены) из сборок, содержащих только метаданные.
- Ссылочная сборка содержит ссылки только на необходимые компоненты в слое доступа API. Реальная сборка может иметь дополнительные ссылки, связанные с конкретной реализацией. Например, ссылочная сборка для
class C { private void M() { dynamic d = 1; ... } }
не ссылается на типы, требуемые дляdynamic
. - Закрытые функции-члены (методы, свойства и события) удаляются в случае, если их удаление не скажется заметно на компиляции. Если нет атрибутов InternalsVisibleTo, внутренние элементы функции также удаляются.
Метаданные в ссылочных сборках продолжают хранить следующие сведения:
- все типы, включая закрытые и вложенные;
- все атрибуты, даже внутренние;
- все виртуальные методы;
- явные реализации интерфейса;
- явно реализованные свойства и события, так как их методы доступа являются виртуальными;
- все поля структур.
Ссылочные сборки содержат атрибут ReferenceAssembly уровня сборки. Этот атрибут может быть задан в исходном коде, в таком случае компилятору не требуется его синтезировать. Из-за этого атрибута среды выполнения не будут загружать ссылочные сборки для выполнения (однако они могут загружаться в режиме только для отражения).
Точные сведения о структуре ссылочной сборки зависят от версии компилятора. Более новые версии могут исключить дополнительные метаданные, если они не влияют на общедоступный API-интерфейса.
Note
Сведения в этом разделе применимы только к ссылочным сборкам, которые созданы компиляторами Roslyn, начиная с C# версии 7.1 или Visual Basic версии 15.3. Структура ссылочных сборок для библиотек .NET Framework и .NET Core может отличаться некоторыми деталями, так как они используют собственный механизм создания ссылочных сборок. Например, они могут иметь совершенно пустые тела методов вместо тела throw null
. Но общие принципы по-прежнему применяются: у них нет пригодных для использования реализаций методов и они содержат метаданные только для элементов, которые имеют наблюдаемый эффект с точки зрения общедоступного API-интерфейса.