¿Cómo funciona exactamente la propiedad "Versión específica" de una referencia de ensamblaje en Visual Studio?

156

Hoy eché un vistazo más de cerca a la propiedad "Versión específica" de las referencias de ensamblaje en Visual Studio 2010. Después de algunos experimentos con resultados inesperados, me propuse aprender lo más posible sobre cómo funciona la propiedad. Incluso SO, me parece, no tiene todas las respuestas, así que aquí está mi intento de responder la pregunta:

¿Cómo funciona exactamente la propiedad "Versión específica" de una referencia de ensamblaje en Visual Studio?

herzbube
fuente

Respuestas:

255

¡Es una propiedad de tiempo de compilación!

Una de las cosas más importantes que debe saber es que la "Versión específica" es una propiedad que tiene efecto en tiempo de compilación y no en tiempo de ejecución.

¿Que es todo esto?

Cuando se construye un proyecto, las referencias de ensamblaje del proyecto deben resolverse para encontrar los ensamblajes físicos que el sistema de compilación debe usar. Si se realiza la verificación "Versión específica" (consulte la sección "¿Cuándo se verifica" Versión específica "?"), Esto afecta el resultado del proceso de resolución del ensamblaje:

  • El sistema de compilación localiza un ensamblaje físico que potencialmente puede usar
  • El sistema de compilación compara la versión del ensamblaje físico con la versión del ensamblaje almacenada en el archivo .csproj para la referencia del ensamblaje
  • Si las dos versiones de ensamblaje son exactamente iguales, el proceso de resolución tiene éxito y el ensamblaje físico encontrado se utiliza para la compilación
  • Si las dos versiones de ensamblaje no coinciden, el ensamblaje físico se descarta y el proceso de resolución continúa localizando el siguiente ensamblaje potencial
  • Si no se pueden ubicar más ensamblajes físicos potenciales, el proceso de resolución falla. Esto da como resultado una advertencia del compilador (advertencia MSB3245) que le indica que no se pudo resolver la referencia.
  • Curiosamente, la construcción continúa. Si el código no tiene referencias reales al ensamblado, la compilación se realiza correctamente (con la advertencia mencionada anteriormente). Si el código tiene referencias, la compilación falla con un error que parece que el código estaba usando tipos o espacios de nombres desconocidos. La única indicación de por qué la compilación realmente falló es la advertencia MSB3245.

Orden en que se resuelven los ensamblajes

El orden en el que el proceso de resolución de ensamblaje localiza ensamblajes potenciales parece ser este:

  1. El ensamblado al que hace referencia el <HintPath>elemento en el archivo .csproj
  2. La ruta de salida del proyecto
  3. El GAC

Tenga en cuenta que si existen varias versiones del ensamblaje en el GAC, el proceso de resolución primero intenta resolver el ensamblaje con la versión más alta. Esto es importante solo si no se realiza la comprobación de "Versión específica".

¿Cuándo se marca "Versión específica"?

Visual Studio basa su decisión de realizar la verificación de "Versión específica" en dos piezas de información que se encuentran en el archivo .csproj:

  • La presencia o ausencia del <SpecificVersion>elemento y su valor (si está presente)
  • La presencia o ausencia de información de versión en la referencia del ensamblaje

Así es como se ve una referencia de ensamblaje típica con información de versión:

<Reference Include="Foo, Version=1.2.3.4, Culture=neutral, processorArchitecture=MSIL">
  <SpecificVersion>True</SpecificVersion>
  <HintPath>..\..\Bar\Foo.dll</HintPath>
</Reference>

Y así es como se ve la referencia de ensamblaje sin información de versión:

<Reference Include="Foo">
[...]

La siguiente tabla muestra cuándo se realiza la comprobación de "Versión específica" y cuándo no.

                            |     Version information
                            |  Present       Not present
----------------------------+------------------------------
<SpecificVersion>           |
- 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)

Lo sorprendente aquí es que no se realiza ninguna verificación si tanto la <SpecificVersion>información de la versión como la ausencia están presentes (caso 6). Hubiera esperado que se realizara la verificación y que siempre fallara (igual que en el caso 2) porque, a mi entender, la ausencia de <SpecificVersion>implica el valor predeterminado "Verdadero". Esto puede ser una peculiaridad de Visual Studio 2010 donde hice mis pruebas.

Cuando examina las propiedades de una referencia de ensamblaje en la interfaz de usuario de Visual Studio (seleccione la referencia y presione F4), el valor que ve para la propiedad "Versión específica" le indica si Visual Studio realizará o no la "Versión específica" cheque. En el caso 6, la IU mostrará "Verdadero", aunque el <SpecificVersion>elemento no está presente en el archivo .csproj.

Efectos secundarios en "Copiar local"

Si la propiedad "Copiar local" se establece en "Verdadero" pero el proceso de resolución del ensamblado falla debido a la verificación de "Versión específica", no se copia ningún ensamblaje.

Material de referencia

herzbube
fuente
Gracias por el detalle ¿Puedo verificar ... la verificación de la versión de ensamblaje solo ocurre para ensamblajes con nombres seguros; ¿está bien? Además, cuando hablamos de verificar la versión de un ensamblaje, ¿se hace comparando el nombre del ensamblado al que se hace referencia ? (En el caso de un ensamblado con nombre seguro, ese nombre incluye la información de la versión, ¿no es así como se verifica un campo de versión separado?)
Gavin Hope
2
@GavinHope Pregunta 1: No, la verificación de la versión no se limita a nombres seguros, principalmente porque un nombre de ensamblado puede incluir la versión pero aún no ser un nombre seguro (por ejemplo, si le falta la PublicKeyToken=parte). Además, si revisa la tabla hacia el final de mi publicación, puede ver que la verificación de la versión puede ocurrir incluso si la Version=parte falta en el nombre del ensamblado en el .csproj. Pregunta 2: Supongo que el nombre del ensamblado se usa para la comparación, sí. No sabría de ninguna otra fuente de información.
herzbube
"En el caso 6, la IU mostrará" True ", aunque el elemento <SpecificVersion> no está presente en el archivo .csproj". - Parece que el valor predeterminado es True . Después de alternar Versión específica en la IU a Verdadero, la <SpecificVersion>etiqueta se omitió por completo, lo que anteriormente tenía un valor de Falso .
samis
@herzbube: creo que el significado de "Versión específica" en la ventana Visual Studio> Propiedades del proyecto es lo contrario de lo que está diciendo aquí (que es lo contrario de lo que esperaría). Visual Studio dice que el valor (verdadero o falso) de "Versión específica" "indica si este conjunto se puede resolver sin tener en cuenta las reglas de orientación múltiple para la resolución del conjunto".
N73k
35

Cuando agrega una referencia, Visual Studio registra la [Versión de ensamblaje] del ensamblaje en el archivo del proyecto. Esto es importante. Si, por ejemplo, crea una corrección de errores un año después, entonces quiere asegurarse de reconstruir el proyecto con la misma versión exacta de la referencia para que sea un verdadero complemento. Obtendrá un error si el ensamblaje de referencia ha cambiado.

Pero eso no siempre es deseable. Algunos programadores permiten que la versión de ensamblaje se incremente automáticamente, generando una nueva versión cada vez que se reconstruyen. Aunque la interfaz pública de la asamblea nunca cambió. Algunos configuran su proyecto usando Nuget para obtener bibliotecas y lo dejan actualizar automáticamente la biblioteca cuando hay una nueva versión disponible. Les gustaría establecer la propiedad Versión específica en False para suprimir el error de compilación.

Bastante importante para entender la consecuencia, es necesario volver a implementar toda la compilación del programa para evitar accidentes. Los desajustes de versión en tiempo de ejecución bloquean el programa y solo se pueden suprimir con un <bindingRedirect>archivo .config que es arriesgado.

Hans Passant
fuente
2
Gracias por la información por la cual "Versión específica" es importante, este es un buen compañero de los aspectos puramente mecánicos que estoy cubriendo en mi respuesta.
herzbube
@Hans Passant: ¿su último párrafo es válido para la versión específica True o False? Creo que estas son las consecuencias cuando lo configuras como verdadero.
GreenEyedAndy
1
La versión específica solo se aplica a la creación de su aplicación. En tiempo de ejecución, el CLR siempre insiste en una coincidencia exacta con el número de versión del ensamblado de referencia. Si usó una versión más nueva en el momento de la compilación, también debe ser esa versión más nueva en tiempo de ejecución.
Hans Passant
1
Tenga cuidado con VS2013 y .Net 4.5.1 AutoGenerateBindingRedirects Pueden redirigir el enlace dll a una versión más nueva aunque le haya dicho que use una versión específica
Dennis Kuypers
1
@HansPassant Pensé que el CLR no tiene en cuenta [AssemblyVersion]cuando los ensamblados no tienen un nombre seguro firmado.
tm1