Подтвердить что ты не робот

Использование нескольких версий одной и той же библиотеки DLL

Мне было поручено создать новый модуль для приложения, и поэтому я добавляю в проект новые библиотеки DLL. Все хорошо и хорошо.

Однако в моих DLL я бы хотел использовать новую версию внешней DLL (над которой я не контролирую). Если я просто ссылаюсь на новую DLL и работаю только с этим, мой код будет работать, но старый код перестанет работать.

Could not load file or assembly 'itextsharp, Version=5.0.6.0, Culture=neutral,
PublicKeyToken=8354ae6d2174ddca' or one of its dependencies. The located assembly's
manifest definition does not match the assembly reference. (Exception from HRESULT:
0x80131040)

Я пробовал простой трюк по изменению имени DLL, но, по-видимому, это было слишком наивно, полагая, что это сработает. Я пытался использовать внешние псевдонимы (определяя их в своих ссылках), но я до сих пор не знаю, как получить два файла с тем же именем в одной папке BIN...

Что мне делать?

4b9b3361

Ответ 1

Вы можете загрузить другую версию в конкретный AppDomain

Возможно, слишком подробно, но вот статья, которая демонстрирует использование AppDomains в полезной настройке и как они работают:

http://msdn.microsoft.com/en-us/magazine/cc164072.aspx

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

    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
    ...

    static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        if (/*some condition*/)
            return Assembly.LoadFrom("DifferentDllFolder\\differentVersion.dll");
        else
            return Assembly.LoadFrom("");
    }

Ответ 3

Вы также можете полагаться на перенаправление привязки сборки для своей сильной именованной сборки, как описано в http://msdn.microsoft.com/en-us/library/2fc472t2.aspx.

У вас будет только одна версия файла (последняя), и обе ссылки разрешат его.

Ответ 4

Если решение AppDomains не применимо в вашем случае, вы находитесь под давлением времени, имеете противоречивые требования (как это когда-либо случается) и не возражаете против смехотворно выдуманных хаков:

  • Декомпилируйте новую версию сборки, используя инструмент ildasm (часть командной строки Developer, включенная в Visual Studio)
  • Отредактируйте сгенерированный файл .il, чтобы найти/заменить ссылки пространства имен сборки. Используя приведенный пример, это будет изменение от itextsharp.X до itextsharp.new.X
  • Аналогичным образом отредактируйте значение для атрибута AssemblyTitleAttribute. Это требует перевода символов ASCII в hex.
  • Скомпилируйте файл .il с помощью ilasm
  • Обратите внимание, что это может потребоваться повторить для любых зависимых сборок (например, someassembly.core.whatever)
  • Добавьте новые .dll в свой проект с другим именем и укажите их явно (а не через nuget или что-то еще)
Эй, не смотри на меня так. Я действительно сказал нелепо надуманный взлом...

Ответ 5

Предположим, что у вас есть структура проекта следующим образом:

Схема проекта

... где A и B - это библиотеки классов, а C - это проект исполняемого типа (например, unit тест или консольный проект).

Предположим, что структура папок такова:

<Предварительно > <код > ABC.sln А /A.csproj A/... Б /B.csproj B/... С /C.csproj C/... Библиотека /thirdparty 4/thirdparty.dll Библиотека/thirdparty5/thirdparty.dll Код >

Если бы мы попытались наивно ссылаться на наши проекты вместе, у нас возникла бы проблема: две версии thirdparty.dll будут скопированы в одну и ту же папку (каталог вывода (т.е. bin) <код > Скод > ). Нам нужен способ C скопировать обе библиотеки dll в его выходной каталог и предоставить механизм для ссылки на один.

Чтобы решить эту проблему, я модифицировал C.csproj, чтобы содержать следующее:

<Предварительно > <код > <ItemGroup> < Content Include = "..\lib\thirdparty4\thirdparty.dll" >   <CopyToOutputDirectory> PreserveNewest </CopyToOutputDirectory>   < & Ссылка GT; thirdparty4\thirdparty.dll </Ссылка > </Содержание > < Content Include = "..\lib\thirdparty5\thirdparty.dll" >   <CopyToOutputDirectory> PreserveNewest </CopyToOutputDirectory>   < & Ссылка GT; thirdparty5\thirdparty.dll </Ссылка > </Содержание > </ItemGroup> Код >

Это даст указание создать в своем выходном каталоге как thirdparty4\thirdparty.dll, так и thirdparty5\thirdparty.dll.

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

<Предварительно > <код > C\Bin\Debug\A.DLL C\Bin\Debug\B.dll C\Bin\Debug\C.dll C\Bin\Debug\thirdparty4\thirdparty.dll C\Bin\Debug\thirdparty5\thirdparty.dll Код >

Чтобы проинструктировать C для использования обеих этих библиотек, я добавил к нему файл App.config со следующим:

  <? xml version = "1.0" encoding = "utf-8"? >
< & конфигурация GT; < & выполнение GT;   < assemblyBinding xmlns = "urn: schemas-microsoft-com: asm.v1" >     <dependentAssembly>       < assemblyIdentity name=  "thirdparty"  culture =  "neutral"  publicKeyToken =  "1234567890123445" />       < bindingRedirect oldVersion = "4.0.0.0-4.0.0.0" newVersion =  "4.0.0.0" />       < codeBase version =  "4.0.0.0"  href= "thirdparty4\thirdparty.dll" />     </dependentAssembly>     <dependentAssembly>       < assemblyIdentity name=  "thirdparty"  culture =  "neutral"  publicKeyToken =  "1234567890123445" />       < bindingRedirect oldVersion = "5.0.0.0-5.0.0.0" newVersion =  "5.0.0.0" />       < codeBase version =  "5.0.0.0"  href= "thirdparty5\thirdparty.dll" />     </dependentAssembly>   </assemblyBinding></Л;/& выполнения GT;
</конфигурации >
Код>

Это даст указание сборке, в зависимости от того, какая версия нужна, использовать одну DLL или другую, которые будут доступны в подпапках выходного каталога. (bindingRedirect являются необязательными, но вы можете использовать их, если вам нужен ряд изменений для этого.)