Como exatamente a propriedade “Versão específica” de uma referência de assembly funciona no Visual Studio?

Hoje eu dei uma olhada mais de perto na propriedade “Versão específica” das referências de assembly no Visual Studio 2010. Depois de algumas experiências com resultados inesperados, comecei a aprender o máximo possível sobre como a propriedade funciona. Mesmo assim, parece-me, não tem todas as respostas, então aqui está minha tentativa de auto-responder a pergunta:

Como exatamente a propriedade “Versão específica” de uma referência de assembly funciona no Visual Studio?

É uma propriedade em tempo de compilation!

Uma das coisas mais importantes a saber é que “Versão específica” é uma propriedade que entra em vigor em tempo de compilation e não em tempo de execução.

Sobre o que é tudo isso?

Quando um projeto é criado, as referências de assembly do projeto precisam ser resolvidas para localizar os conjuntos físicos que o sistema de compilation deve usar. Se a verificação “Versão específica” for executada (consulte a seção “Quando a” Versão específica “está marcada?”), Ela afeta o resultado do processo de resolução da assembly:

  • O sistema de compilation localiza uma assembly física que pode potencialmente usar
  • O sistema de compilation compara a versão do assembly físico para a versão do assembly armazenada no arquivo .csproj para a referência de assembly
  • Se as duas versões de assembly forem exatamente iguais, o processo de resolução será bem-sucedido e o conjunto físico encontrado será usado para a compilation
  • Se as duas versões de assembly não corresponderem, a assembly física será descartada e o processo de resolução continuará, localizando o próximo conjunto em potencial
  • Se não houver mais montagens físicas em potencial, o processo de resolução falhará. Isso resulta em um aviso de compilador (aviso MSB3245) que informa que a referência não pôde ser resolvida.
  • Curiosamente, a construção continua! Se o código não tiver referências reais à assembly, a compilation terá êxito (com o aviso mencionado anteriormente). Se o código tiver referências, a criação falhará com um erro que parece que o código estava usando tipos desconhecidos ou namespaces. A única indicação porque a compilation realmente falhou é o aviso MSB3245.

Ordem em que as montagens são resolvidas

A ordem em que o processo de resolução de assembly localiza possíveis montagens parece ser o seguinte:

  1. O assembly referenciado pelo elemento no arquivo .csproj
  2. O caminho de saída do projeto
  3. O GAC

Observe que, se várias versões do assembly existirem no GAC, o processo de resolução primeiro tenta resolver o assembly com a versão mais alta. Isso é importante somente se a verificação “Versão específica” não for feita.

Quando a “Versão específica” é verificada?

O Visual Studio baseia sua decisão de executar a verificação “Versão específica” em duas partes de informações encontradas no arquivo .csproj:

  • A presença ou ausência do elemento e seu valor (se estiver presente)
  • A presença ou ausência de informações de versão na referência de assembly

É assim que uma referência de assembly típica com informações de versão é semelhante:

  True ..\..\Bar\Foo.dll  

E é assim que a referência de assembly se parece sem informações de versão:

  [...] 

A tabela a seguir mostra quando a verificação “Versão específica” é executada e quando não é.

  | Version information | Present Not present ----------------------------+------------------------------  | - Present, has value True | Yes (1) Yes (check always fails) (2) - Present, has value False | No (3) No (4) - Not present | Yes (5) No (6) 

O surpreendente é que nenhuma verificação é realizada se ambas as informações e versão estiverem ausentes (caso 6). Eu esperaria que a verificação fosse executada e sempre falhasse (como no caso 2) porque, no meu entendimento, a ausência de implica o valor padrão “True”. Isso pode ser um capricho do Visual Studio 2010, onde fiz meus testes.

Quando você examinar as propriedades de uma referência de assembly na interface do Visual Studio (selecione a referência e pressione F4), o valor que você vê para a propriedade “versão específica” informa se ou não Visual Studio vai executar a “versão específica” Verifica. No caso 6, a interface do usuário mostrará “True”, embora o elemento não esteja presente no arquivo .csproj.

Efeitos colaterais em “Copiar local”

Se a propriedade “Copy Local” estiver definida como “True”, mas o processo de resolução de assembly falhar por causa da verificação “Versão específica”, nenhum assembly será copiado.

Material de referência

  • O que você precisa saber sobre os assemblies referenciados no VS2005 (artigo blogs.msdn.com)
  • O que há de novo no .NET 2.0 para Assemblies e Versioning? (artigo codemag.com que reproduz o artigo do MSDN acima, até o texto, mas contém algumas capturas de canvas e informações adicionais sobre o versionamento de assembly)

Quando você adiciona uma referência, o Visual Studio registra a [AssemblyVersion] da assembly no arquivo de projeto. Isso é importante. Se você, digamos, criar uma correção de bug um ano depois, então você quer ter certeza de que você reconstruiu o projeto com a mesma versão exata da referência, então é um verdadeiro drop-in. Você receberá um erro se o conjunto de referência foi alterado.

Mas isso nem sempre é desejável. Alguns programadores permitem que a versão do assembly seja incrementada automaticamente, gerando uma nova versão toda vez que eles são reconstruídos. Mesmo que a interface pública da assembly nunca tenha mudado. Alguns configuram seu projeto usando o Nuget para obter bibliotecas e permitir que ele atualize automaticamente a biblioteca quando houver uma nova versão disponível. Eles desejarão configurar a propriedade Versão específica como False para suprimir o erro de compilation.

Bastante importante para entender a consequência, você precisa reimplantar toda a compilation do programa para evitar acidentes. As incompatibilidades de versão no tempo de execução travam o programa e só podem ser suprimidas com um no arquivo .config que é arriscado.