Jak dokładnie działa właściwość „Określona wersja” odwołania do zestawu w programie Visual Studio?

155

Dzisiaj przyjrzałem się bliżej właściwości "Specific Version" odwołań do zestawu w Visual Studio 2010. Po kilku eksperymentach z nieoczekiwanymi wynikami postanowiłem dowiedzieć się jak najwięcej o tym, jak działa ta właściwość. Nawet TAK, jak mi się wydaje, nie ma wszystkich odpowiedzi, więc oto moja próba samodzielnej odpowiedzi na pytanie:

Jak dokładnie działa właściwość „Określona wersja” odwołania do zestawu w programie Visual Studio?

herzbube
źródło

Odpowiedzi:

255

To właściwość czasu kompilacji!

Jedną z najważniejszych rzeczy, o których należy wiedzieć, jest to, że „Określona wersja” to właściwość, która obowiązuje w czasie kompilacji, a nie w czasie wykonywania.

O co w tym wszystkim chodzi?

Podczas budowania projektu należy rozwiązać odniesienia do zestawu projektu, aby znaleźć fizyczne zestawy, których powinien używać system kompilacji. Jeśli sprawdzana jest „Określona wersja” (patrz sekcja „Kiedy jest sprawdzana„ Określona wersja ”?”), Ma to wpływ na wynik procesu rozwiązywania zespołu:

  • System kompilacji lokalizuje fizyczny zestaw, którego może potencjalnie użyć
  • System kompilacji porównuje wersję zestawu fizycznego z wersją zestawu przechowywaną w pliku .csproj dla odwołania do zestawu
  • Jeśli dwie wersje zestawu są dokładnie takie same, proces rozwiązywania powiedzie się, a znaleziony zestaw fizyczny jest używany do kompilacji
  • Jeśli dwie wersje zestawu nie są zgodne, fizyczny zestaw jest odrzucany, a proces rozwiązywania jest kontynuowany poprzez zlokalizowanie następnego potencjalnego złożenia
  • Jeśli nie można zlokalizować więcej potencjalnych zestawów fizycznych, proces rozwiązywania nie powiedzie się. Powoduje to ostrzeżenie kompilatora (ostrzeżenie MSB3245) informujące, że nie można rozwiązać odwołania.
  • Co ciekawe, budowa jest kontynuowana! Jeśli kod nie ma rzeczywistych odwołań do zestawu, kompilacja powiedzie się (z wcześniej wspomnianym ostrzeżeniem). Jeśli kod zawiera odwołania, kompilacja kończy się niepowodzeniem z błędem, który wygląda tak, jakby kod używał nieznanych typów lub przestrzeni nazw. Jedyną wskazówką, dlaczego kompilacja naprawdę się nie powiodła, jest ostrzeżenie MSB3245.

Kolejność, w jakiej zespoły są rozwiązywane

Wydaje się, że kolejność, w jakiej proces rozwiązywania zespołu lokalizuje potencjalne zestawy, jest następująca:

  1. Zestaw, do którego odwołuje się <HintPath>element w pliku .csproj
  2. Ścieżka wyjściowa projektu
  3. GAC

Należy zauważyć, że jeśli w GAC istnieje kilka wersji zestawu, proces rozpoznawania najpierw próbuje rozwiązać zestaw z najwyższą wersją. Jest to ważne tylko wtedy, gdy nie jest sprawdzana „Określona wersja”.

Kiedy jest zaznaczana „Określona wersja”?

Program Visual Studio opiera swoją decyzję, czy sprawdzić „określoną wersję”, na dwóch informacjach znajdujących się w pliku .csproj:

  • Obecność lub brak <SpecificVersion>elementu i jego wartość (jeśli występuje)
  • Obecność lub brak informacji o wersji w odwołaniu do zestawu

Oto jak wygląda typowe odwołanie do zestawu z informacjami o wersji:

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

A tak wygląda odwołanie do zestawu bez informacji o wersji:

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

W poniższej tabeli przedstawiono, kiedy przeprowadzane jest sprawdzenie „określonej wersji”, a kiedy nie.

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

Zaskakujące jest tutaj to, że żadne sprawdzenie nie jest wykonywane, jeśli <SpecificVersion>nie ma informacji o wersji i wersji (przypadek 6). Spodziewałbym się, że sprawdzenie zostanie wykonane i zawsze zakończy się niepowodzeniem (tak samo jak w przypadku 2), ponieważ w moim rozumieniu brak <SpecificVersion>implikuje domyślną wartość „True”. Może to być dziwactwo programu Visual Studio 2010, w którym przeprowadzałem testy.

Podczas sprawdzania właściwości odwołania do zestawu w interfejsie użytkownika programu Visual Studio (wybierz odwołanie i naciśnij klawisz F4), wartość widoczna dla właściwości „Określona wersja” informuje, czy program Visual Studio wykona „Określoną wersję” czek. W przypadku 6 interfejs użytkownika pokaże „True”, chociaż <SpecificVersion>elementu nie ma w pliku .csproj.

Skutki uboczne „Kopiuj lokalnie”

Jeśli właściwość „Kopiuj lokalnie” jest ustawiona na „Prawda”, ale proces rozwiązywania zespołu kończy się niepowodzeniem z powodu sprawdzenia „Określonej wersji”, żaden zestaw nie jest kopiowany.

Materiał referencyjny

herzbube
źródło
Dzięki za szczegóły. Czy mogę po prostu sprawdzić ... Sprawdzanie wersji zestawu ma miejsce tylko w przypadku zestawów o silnych nazwach; czy to prawda? Również, gdy mówimy o sprawdzenie wersji zespół - jest to, że odbywa się przez porównanie odwołuje Zgromadzenia nazwy ? (W przypadku zestawu o silnej nazwie nazwa ta zawiera informacje o wersji, więc nie jest tak, że jest sprawdzane oddzielne pole wersji?)
Gavin Hope,
2
@GavinHope Pytanie 1: Nie, sprawdzanie wersji nie ogranicza się do silnych nazw, głównie dlatego, że nazwa zespołu może zawierać wersję, ale nadal nie może być silną nazwą (np. Jeśli brakuje PublicKeyToken=części). Ponadto, jeśli sprawdzisz tabelę pod koniec mojego postu, zobaczysz, że sprawdzanie wersji może nastąpić, nawet jeśli Version=brakuje części w nazwie zespołu w .csproj. Pytanie 2: Zakładam, że do porównania używana jest nazwa zespołu, tak. Nie znam żadnego innego źródła informacji.
herzbube
„W przypadku 6 interfejs użytkownika pokaże„ True ”, chociaż element <SpecificVersion> nie występuje w pliku .csproj.” - Wygląda na to, że wartość domyślna to True . Po przełączanie konkretnej wersji w interfejsie użytkownika do True powoduje<SpecificVersion> tag został całkowicie pominięty, który wcześniej miał wartość Fałsz .
samis
@herzbube - Myślę, że znaczenie „Określona wersja” w oknie Visual Studio> Właściwości projektu jest przeciwieństwem tego, co tutaj mówisz (co jest przeciwieństwem tego, czego można się spodziewać). Program Visual Studio twierdzi, że wartość (prawda lub fałsz) „Określona wersja” „wskazuje, czy ten zestaw może zostać rozwiązany bez uwzględniania reguł kierowania na wiele elementów dotyczących rozpoznawania zestawu”.
N73k
35

Po dodaniu odwołania program Visual Studio rejestruje [AssemblyVersion] zestawu w pliku projektu. To jest ważne. Jeśli, powiedzmy, utworzysz naprawę błędu rok później, będziesz chciał się upewnić, że przebudujesz projekt z dokładnie tą samą wersją odniesienia, aby był to prawdziwy drop-in. Otrzymasz błąd, jeśli zestaw referencyjny został zmieniony.

Ale to nie zawsze jest pożądane. Niektórzy programiści pozwalają automatycznie zwiększać wersję zestawu, generując nową wersję za każdym razem, gdy przebudowują. Mimo że publiczny interfejs zestawu nigdy się nie zmienił. Niektórzy konfigurują swój projekt za pomocą Nuget w celu uzyskania bibliotek i pozwalają na automatyczne aktualizowanie biblioteki, gdy jest dostępna nowa wersja. Będą chcieli ustawić właściwość Specific Version na False, aby powstrzymać błąd kompilacji.

Bardzo ważne, aby zrozumieć konsekwencje, musisz ponownie wdrożyć całą kompilację programu, aby uniknąć wypadków. Niezgodność wersji w czasie wykonywania powoduje awarię programu i można ją zlikwidować tylko za pomocą <bindingRedirect>znaku w pliku konfiguracyjnym, co jest ryzykowne.

Hans Passant
źródło
2
Dzięki za informację, dlaczego „Konkretna wersja” jest ważna, jest to dobry dodatek do czysto mechanicznych aspektów, które omawiam w mojej odpowiedzi.
herzbube
@Hans Passant - czy ostatni akapit dotyczy wersji SpecificVersion True czy False? Myślę, że takie są konsekwencje, kiedy ustawisz to na prawdę.
GreenEyedAndy
1
SpecificVersion dotyczy tylko tworzenia aplikacji. W czasie wykonywania środowisko CLR zawsze nalega na dokładne dopasowanie z numerem wersji zestawu odniesienia. Jeśli użyłeś nowszej wersji w czasie kompilacji, musi to być również nowsza wersja w czasie wykonywania.
Hans Passant
1
Uważaj na VS2013 i .Net 4.5.1 AutoGenerateBindingRedirects Mogą przekierować powiązanie dll do nowszej wersji, nawet jeśli kazałeś mu używać określonej wersji
Dennis Kuypers
1
@HansPassant Myślałem, że CLR nie bierze pod uwagę, [AssemblyVersion]gdy zestawy nie są podpisane silną nazwą.
tm1