Compartilhar via


Assemblies 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ários para representar a superfície da API pública da biblioteca. Eles incluem declarações para todos os membros que são significativas ao referenciar um assembly em ferramentas de build, mas excluem todas as implementações de membros e declarações de membros privados que não têm nenhum impacto observável em seu contrato de API. Por outro lado, assemblies regulares são chamadas de 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 SDK (Software Development Kit) de uma plataforma ou biblioteca específica.

O uso de um assembly de referência permite que os desenvolvedores criem programas direcionados a uma versão de biblioteca específica 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 seu computador, mas deseja criar um programa direcionado 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 no computador de destino. Se você compilar no assembly de referência para a versão anterior, receberá imediatamente um erro de 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 dão suporte ao 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 diferentes plataformas, como mscorlib.dll no .NET Framework ou System.Private.CoreLib.dll no .NET Core. Uma biblioteca direcionada ao .NET Standard pode ser executada em todas as plataformas compatíveis com o .NET Standard.

Usando assemblies de referência

Para usar determinadas APIs do seu projeto, é necessário adicionar referências às suas bibliotecas. Você pode adicionar referências a assemblies de implementação ou a assemblies de referência. É recomendável que você use assemblies de referência sempre que eles estiverem disponíveis. Isso garante que você esteja usando apenas os membros da API com suporte na versão de destino, destinados a serem usados por designers de API. O uso do assembly de referência garante que você não esteja usando uma dependência dos detalhes da implementação.

Os assemblies de referência para as bibliotecas .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 .NET Core e .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 antes da 3.0).

Ao adicionar 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 ao projeto MSBuild usando o item de projeto Referência: você só precisa especificar o nome do assembly, não o caminho de arquivo completo. Ao adicionar referências a esses assemblies na linha de comando usando a opção do -reference 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 no %ProgramFiles(x86)%\Reference Assemblies\Microsoft\Framework\.NETFramework diretório. 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 do PreserveCompilationContext projeto como true. Em seguida, você pode passar esses arquivos de assembly de referência para o compilador. O uso do DependencyContext do pacote Microsoft.Extensions.DependencyModel pode ajudar a localizar os caminhos deles.

Como eles não contêm nenhuma implementação, os assemblies de referência não podem ser carregados para execução. Tentar fazer isso resulta em um System.BadImageFormatException. Se 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 método Assembly.ReflectionOnlyLoad ) ou no MetadataLoadContext no .NET e no .NET Framework.

Gerando assemblies de referência

Gerar assemblies de referência para suas bibliotecas pode ser útil quando os consumidores da biblioteca precisarem criar seus programas em relação a muitas versões diferentes da biblioteca. A distribuição de 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 build também podem aproveitar os assemblies de referência para reduzir os tempos de build em caso de soluções grandes que consistem em várias bibliotecas de classes. Normalmente, em cenários de build incrementais, um projeto é recriado 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 muda a implementação de qualquer membro. O assembly de referência só é alterado quando sua API pública é afetada. Portanto, 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 você quiser distribuir assemblies de referência com pacotes NuGet, deverá incluí-los no subdiretório ref\ no diretório do pacote em vez do subdiretório lib\ usado para assemblies de implementação.

Estrutura de conjuntos de referência

Conjuntos de referência são uma expansão do conceito relacionado, conjuntos somente de metadados. Os assemblies somente de metadados têm seus corpos de método substituídos por um único corpo throw null, mas incluem todos os membros, exceto tipos anônimos. O motivo para usar corpos throw null (em vez de nenhum corpo) é que PEVerify poderia ser executado e passado (validando, assim, a integridade dos metadados).

Os assemblies de referência removem ainda mais metadados (membros particulares) de assemblies somente de metadados:

  • Um assembly de referência tem somente referências para o que ele precisa na superfície de API. A montagem real pode ter mais referências relacionadas a implementações específicas. Por exemplo, o assembly de referência para class C { private void M() { dynamic d = 1; ... } } não referencia nenhum tipo necessário para dynamic.
  • Membros de função privada (métodos, propriedades e eventos) são removidos em casos em que sua remoção não afeta observavelmente a compilação. Se não houverem atributos InternalsVisibleTo, os membros de funções internas 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 implementados explicitamente, porque seus acessadores são virtuais.
  • Todos os campos de estruturas.

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

Os detalhes exatos da estrutura do assembly de referência dependem da versão do compilador. As versões mais recentes poderão optar por excluir mais metadados se forem determinadas como não afetando a superfície da API pública.

Observação

As informações nesta seção são aplicáveis somente a assemblies de referência gerados por compiladores Roslyn a partir do C# versão 7.1 ou do Visual Basic versão 15.3. A estrutura de assemblies de referência para bibliotecas do .NET Framework e do .NET Core pode diferir em alguns detalhes, pois elas 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 corpo throw null. 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 da perspectiva da API pública.

Consulte também