Как именно свойство «Конкретная версия» ссылки на сборку работает в Visual Studio?

156

Сегодня я подробнее рассмотрел свойство «Конкретная версия» ссылок на сборки в Visual Studio 2010. После нескольких экспериментов с неожиданными результатами я решил узнать как можно больше о том, как работает это свойство. Даже ТАК, как мне кажется, не все ответы, поэтому вот моя попытка ответить на вопрос:

Как именно работает свойство «Конкретная версия» ссылки на сборку в Visual Studio?

herzbube
источник

Ответы:

255

Это свойство времени компиляции!

Одна из самых важных вещей, которую нужно знать, это то, что «Конкретная версия» - это свойство, которое вступает в силу во время компиляции, а не во время выполнения.

О чем это все?

Когда проект создается, ссылки на сборки проекта должны быть разрешены, чтобы найти физические сборки, которые должна использовать система сборки. Если выполняется проверка «Определенная версия» (см. Раздел «Когда проверяется« Определенная версия »?»), Это влияет на результат процесса разрешения сборки:

  • Система сборки находит физическую сборку, которую она потенциально может использовать
  • Система сборки сравнивает версию физической сборки с версией сборки, хранящейся в файле .csproj для ссылки на сборку.
  • Если две версии сборки совпадают, процесс разрешения завершается успешно, и найденная физическая сборка используется для сборки.
  • Если две версии сборки не совпадают, физическая сборка отбрасывается, и процесс разрешения продолжается путем поиска следующей потенциальной сборки.
  • Если больше нет потенциальных физических сборок, процесс разрешения не выполняется. Это приводит к предупреждению компилятора (предупреждение MSB3245), в котором говорится, что ссылка не может быть разрешена.
  • Интересно, что сборка продолжается! Если в коде нет фактических ссылок на сборку, сборка завершается успешно (с ранее упомянутым предупреждением). Если в коде есть ссылки, сборка завершается с ошибкой, которая выглядит так, как если бы код использовал неизвестные типы или пространства имен. Единственным признаком того, почему сборка действительно не удалась, является предупреждение MSB3245.

Порядок разрешения сборок

Порядок, в котором процесс разрешения сборки находит потенциальные сборки, выглядит следующим образом:

  1. Сборка, на которую ссылается <HintPath>элемент в файле .csproj
  2. Выходной путь проекта
  3. GAC

Обратите внимание, что если в GAC существует несколько версий сборки, процесс разрешения сначала пытается разрешить сборку с самой высокой версией. Это важно, только если проверка «Конкретная версия» не выполнена.

Когда проверяется «Конкретная версия»?

Visual Studio принимает решение о том, выполнять ли проверку «Определенная версия» на двух фрагментах информации, найденных в файле .csproj:

  • Наличие или отсутствие <SpecificVersion>элемента, а также его значение (если оно присутствует)
  • Наличие или отсутствие информации о версии в сборочной ссылке

Вот так выглядит типичная ссылка на сборку с информацией о версии:

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

А вот так выглядит ссылка на сборку без информации о версии:

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

В следующей таблице показано, когда выполняется проверка «Определенная версия», а когда - нет.

                            |     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)

Здесь удивительно то, что проверка не выполняется, если отсутствуют <SpecificVersion>и информация о версии, и версия (случай 6). Я ожидал, что проверка будет выполнена и всегда будет неудачной (как в случае 2), потому что в моем понимании отсутствие <SpecificVersion>подразумевает значение по умолчанию «True». Это может быть причуда Visual Studio 2010, где я делал свои тесты.

Когда вы исследуете свойства ссылки на сборку в пользовательском интерфейсе Visual Studio (выберите ссылку и нажмите F4), значение, которое вы видите для свойства «Конкретная версия», указывает, будет ли Visual Studio выполнять «Конкретную версию». чек. В случае 6 пользовательский интерфейс покажет «True», хотя <SpecificVersion>элемент отсутствует в файле .csproj.

Побочные эффекты на «Копировать локально»

Если для свойства «Копировать локально» задано значение «Истина», но процесс разрешения сборки не выполняется из-за проверки «Определенная версия», сборка не копируется.

Справочный материал

herzbube
источник
Спасибо за детали. Могу ли я просто проверить ... проверка версии сборки происходит только для сборок со строгими именами; это правильно? Кроме того , когда мы говорим о проверке версии сборки - это делается путем сравнения ссылочных Ассамблей имени ? (В случае сборки со строгим именем это имя включает информацию о версии, так что это не значит, что проверяется отдельное поле версии?)
Гэвин Хоуп
2
@GavinHope Вопрос 1: Нет, проверка версии не ограничивается строгими именами, главным образом потому, что имя сборки может включать версию, но все же не может быть строгим именем (например, если в ней отсутствует PublicKeyToken=деталь). Кроме того, если вы проверите таблицу в конце моего сообщения, вы увидите, что проверка версии может происходить, даже если Version=деталь отсутствует в имени сборки в .csproj. Вопрос 2: я предполагаю, что имя сборки используется для сравнения, да. Я не знал бы ни о каком другом источнике информации.
herzbube
«В случае 6 пользовательский интерфейс покажет« True », хотя элемент <SpecificVersion> отсутствует в файле .csproj.» - Похоже, что значением по умолчанию является True . После переключая конкретной версии в пользовательском интерфейсе в True<SpecificVersion> , тег был полностью опущен, который ранее имел значение Ложь .
Сами
@herzbube - Я думаю, что значение «Определенная версия» в окне Visual Studio> Свойства проекта противоположно тому, что вы здесь говорите (что противоположно тому, что вы ожидаете). Visual Studio говорит, что значение («истина» или «ложь») «Определенная версия» «указывает, может ли эта сборка быть разрешена без учета правил множественного нацеливания для разрешения сборки».
N73k
35

Когда вы добавляете ссылку, Visual Studio записывает [AssemblyVersion] сборки в файл проекта. Это важно. Если вы, скажем, создаете исправление ошибки год спустя, то вы хотите убедиться, что вы перестраиваете проект с точно такой же версией справки, чтобы это было настоящим раскрытием. Вы получите ошибку, если ссылочная сборка изменилась.

Но это не всегда желательно. Некоторые программисты позволяют версии сборки автоматически увеличиваться, генерируя новую версию каждый раз, когда перестраивают. Хотя открытый интерфейс сборки никогда не менялся. Некоторые настраивают свой проект, используя Nuget для получения библиотек, и позволяют ему автоматически обновлять библиотеку при появлении новой версии. Они захотят установить для свойства Specific Version значение False, чтобы подавить ошибку компиляции.

Очень важно понять последствия, вам нужно заново развернуть всю сборку программы, чтобы избежать несчастных случаев. Несовпадение версий во время выполнения приводит к сбою программы и может быть подавлено только с помощью <bindingRedirect>файла .config, который является рискованным.

Ганс Пассант
источник
2
Спасибо за информацию, почему «Конкретная версия» важна, это хороший компаньон с чисто механическими аспектами, которые я освещаю в своем ответе.
herzbube
@Hans Passant - ваш последний абзац действителен для SpecificVersion True или False? Я думаю, что это последствия, когда вы устанавливаете это на истину.
GreenEyedAndy
1
SpecificVersion относится только к созданию вашего приложения. Во время выполнения CLR всегда настаивает на точном соответствии с номером версии эталонной сборки. Если вы использовали более новую версию во время сборки, то она также должна быть более новой во время выполнения.
Ганс Пассант
1
Остерегайтесь VS2013 и .Net 4.5.1 AutoGenerateBindingRedirects Они могут перенаправить привязку dll к более новой версии, даже если вы сказали ей использовать определенную версию
Деннис Кайперс
1
@HansPassant Я думал, что CLR не учитывает, [AssemblyVersion]когда сборки не подписаны.
tm1