Montagens de referência

Os assemblies de referência são um tipo especial de assembly que contém apenas a quantidade mínima de metadados necessária para representar a superfície pública da API da biblioteca. Eles incluem declarações para todos os membros que são significativas ao fazer referência a um assembly em ferramentas de compilação, mas excluem todas as implementações de membros e declarações de membros privados que não têm impacto observável em seu contrato de API. Em contraste, assemblies regulares são chamados assemblies de implementação.

Os assemblies de referência não podem ser carregados para execução, mas podem ser passados como entrada do compilador da mesma forma que os assemblies de implementação. Os assemblies de referência geralmente são distribuídos com o Software Development Kit (SDK) de uma determinada plataforma ou biblioteca.

O uso de um assembly de referência permite que os desenvolvedores criem programas destinados a uma versão específica da biblioteca sem ter o assembly de implementação completo para essa versão. Suponha que você tenha apenas a versão mais recente de alguma biblioteca em sua máquina, mas deseja criar um programa destinado a uma versão anterior dessa biblioteca. Se você compilar diretamente no assembly de implementação, poderá usar inadvertidamente membros da API que não estão disponíveis na versão anterior. Você só encontrará esse erro ao testar o programa na máquina de destino. Se você compilar no assembly de referência para a versão anterior, receberá imediatamente um erro em tempo de compilação.

Um assembly de referência também pode representar um contrato, ou seja, um conjunto de APIs que não correspondem ao assembly de implementação concreto. Esses assemblies de referência, chamados de assembly de contrato, podem ser usados para direcionar várias plataformas que suportam o mesmo conjunto de APIs. Por exemplo, o .NET Standard fornece o assembly de contrato, netstandard.dll, que representa o conjunto de APIs comuns compartilhadas entre diferentes plataformas .NET. As implementações dessas APIs estão contidas em assemblies diferentes em plataformas diferentes, como mscorlib.dll no .NET Framework ou System.Private.CoreLib.dll no .NET Core. Uma biblioteca destinada ao .NET Standard pode ser executada em todas as plataformas que oferecem suporte ao .NET Standard.

Usando assemblies de referência

Para usar determinadas APIs do seu projeto, você deve adicionar referências a seus assemblies. Você pode adicionar referências a assemblies de implementação ou a assemblies de referência. É recomendável usar assemblies de referência sempre que estiverem disponíveis. Isso garante que você esteja usando apenas os membros da API suportados na versão de destino, destinada a ser usada pelos designers de API. O uso do assembly de referência garante que você não dependa dos detalhes da implementação.

Os assemblies de referência para as bibliotecas do .NET Framework são distribuídos com pacotes de destino. Você pode obtê-los baixando um instalador autônomo ou selecionando um componente no instalador do Visual Studio. Para obter mais informações, consulte Instalar o .NET Framework para desenvolvedores. Para o .NET Core e o .NET Standard, os assemblies de referência são baixados automaticamente conforme necessário (via NuGet) e referenciados. Para o .NET Core 3.0 e superior, os assemblies de referência para a estrutura principal estão no pacote Microsoft.NETCore.App.Ref (o pacote Microsoft.NETCore.App é usado em vez disso para versões anteriores à 3.0).

Quando você adiciona referências a assemblies do .NET Framework no Visual Studio usando a caixa de diálogo Adicionar referência , você seleciona um assembly na lista e o Visual Studio localiza automaticamente assemblies de referência que correspondem à versão da estrutura de destino selecionada em seu projeto. O mesmo se aplica à adição de referências diretamente no projeto MSBuild usando o item de projeto de referência : você só precisa especificar o nome do assembly, não o caminho completo do arquivo. Quando você adiciona referências a esses assemblies na linha de comando usando a -reference opção de compilador (em C# e no Visual Basic) ou usando o Compilation.AddReferences método na API Roslyn, você deve especificar manualmente os arquivos de assembly de referência para a versão correta da plataforma de destino. Os arquivos de assembly de referência do .NET Framework estão localizados em %ProgramFiles(x86)%\Reference Assemblies\Microsoft\Framework\. Diretório NETFramework . Para o .NET Core, você pode forçar a operação de publicação para copiar assemblies de referência para sua plataforma de destino no subdiretório publish/refs do diretório de saída definindo a propriedade project PreserveCompilationContext como true. Em seguida, você pode passar esses arquivos de assembly de referência para o compilador. Usar DependencyContext o pacote Microsoft.Extensions.DependencyModel pode ajudar a localizar seus caminhos.

Como eles não contêm nenhuma implementação, os assemblies de referência não podem ser carregados para execução. Tentar fazê-lo resulta em um System.BadImageFormatExceptionarquivo . Se você quiser examinar o conteúdo de um assembly de referência, você pode carregá-lo no contexto somente reflexão no .NET Framework (usando o Assembly.ReflectionOnlyLoad método) ou no MetadataLoadContext .NET e .NET Framework.

Geração de conjuntos de referência

A geração de assemblies de referência para suas bibliotecas pode ser útil quando os consumidores de bibliotecas precisam criar seus programas em relação a muitas versões diferentes da biblioteca. Distribuir assemblies de implementação para todas essas versões pode ser impraticável devido ao seu grande tamanho. Os assemblies de referência são menores em tamanho, e distribuí-los como parte do SDK da biblioteca reduz o tamanho do download e economiza espaço em disco.

IDEs e ferramentas de compilação também podem tirar proveito de assemblies de referência para reduzir os tempos de compilação no caso de grandes soluções que consistem em várias bibliotecas de classe. Normalmente, em cenários de compilação incremental, um projeto é reconstruído quando qualquer um de seus arquivos de entrada é alterado, incluindo os assemblies dos quais depende. A montagem de implementação muda sempre que o programador altera a implementação de qualquer membro. O assembly de referência só muda quando sua API pública é afetada. Assim, usar o assembly de referência como um arquivo de entrada em vez do assembly de implementação permite ignorar a compilação do projeto dependente em alguns casos.

Você pode gerar assemblies de referência:

Se quiser distribuir assemblies de referência com pacotes NuGet, você deve incluí-los no subdiretório ref\ sob o diretório do pacote em vez de no subdiretório lib\ usado para assemblies de implementação.

Estrutura dos conjuntos de referência

Os assemblies de referência são uma expansão do conceito relacionado, assemblies somente de metadados. Os assemblies somente de metadados têm seus corpos de método substituídos por um único throw null corpo, mas incluem todos os membros, exceto os tipos anônimos. A razão para o uso throw null de corpos (em oposição a nenhum corpo) é para que o PEVerify possa ser executado e aprovado (validando assim a completude dos metadados).

Os assemblies de referência removem ainda mais os metadados (membros privados) dos assemblies somente de metadados:

  • Um assembly de referência só tem referências para o que precisa na superfície da API. A montagem real pode ter referências adicionais relacionadas a implementações específicas. Por exemplo, o assembly de referência para class C { private void M() { dynamic d = 1; ... } } não faz referência a nenhum tipo necessário para dynamic.
  • Os membros de funções privadas (métodos, propriedades e eventos) são removidos nos casos em que sua remoção não afeta observável a compilação. Se não houver atributos InternalsVisibleTo, os membros da função interna também serão removidos.

Os metadados em assemblies de referência continuam a manter as seguintes informações:

  • Todos os tipos, incluindo tipos privados e aninhados.
  • Todos os atributos, mesmo os internos.
  • Todos os métodos virtuais.
  • Implementações de interface explícitas.
  • Propriedades e eventos explicitamente implementados, porque seus acessadores são virtuais.
  • Todos os campos das estruturas.

Os assemblies de referência incluem um atributo ReferenceAssembly no nível de assembly. Este atributo pode ser especificado na fonte; então o compilador não precisará sintetizá-lo. Devido a esse atributo, os tempos de execução se recusarão a carregar assemblies de referência para execução (mas eles podem ser carregados no modo somente reflexão).

Os detalhes exatos da estrutura do assembly de referência dependem da versão do compilador. As versões mais recentes podem optar por excluir mais metadados se for determinado que não afetam a superfície pública da API.

Nota

As informações nesta seção são aplicáveis somente a assemblies de referência gerados por compiladores Roslyn a partir de C# versão 7.1 ou Visual Basic versão 15.3. A estrutura dos assemblies de referência para bibliotecas .NET Framework e .NET Core pode diferir em alguns detalhes, porque eles usam seu próprio mecanismo de geração de assemblies de referência. Por exemplo, eles podem ter corpos de método totalmente vazios em vez do throw null corpo. Mas o princípio geral ainda se aplica: eles não têm implementações de método utilizáveis e contêm metadados apenas para membros que têm um impacto observável de uma perspetiva de API pública.

Consulte também