Разница между LoadFile и LoadFrom со сборками .NET?

126

Я смотрел документацию msdn, и я все еще немного смущен тем, в чем именно разница между использованием LoadFileи LoadFromзагрузкой сборки. Может ли кто-нибудь привести пример или аналогию, чтобы лучше описать это. Документация MSDN смутила меня больше. Кроме того, это ReflectionOnlyLoadFromто же самое, LoadFromза исключением того, что он загружает сборку только в режиме отражения.

Поскольку мой опыт работы с .NET не самый лучший, вот несколько вопросов относительно документации MSDN с использованием LoadFile:

1) Что означает LoadFileпроверка сборок с одинаковым идентификатором, но расположенных по разным путям? Какая личность (пример)?

2) Он заявляет, что LoadFileне загружает файлы в «контекст LoadFrom» и не разрешает зависимости с использованием пути загрузки. Что это значит, может кто-нибудь привести пример?

3) Наконец, в нем говорится, что LoadFileэто полезно в этом ограниченном сценарии, поскольку LoadFrom не может загружать сборки с одинаковыми идентификаторами, но разными путями; он загрузит только первую такую ​​сборку, что снова подводит меня к тому же вопросу, какова идентичность сборок?

Xaisoft
источник
10
Серьезно, я также иногда думаю, что MS должен нанять лучших писателей или что-то еще, потому что предложения не всегда понятны ...
Тарик
7
Смотрите также недокументированное
полковник Паник
1
@ColonelPanic MS может сказать, что все задокументировано ... но с нулевым коэффициентом помощи.
Legends

Ответы:

96

Это проясняет?

// path1 and path2 point to different copies of the same assembly on disk:

Assembly assembly1 = Assembly.LoadFrom(path1);
Assembly assembly2 = Assembly.LoadFrom(path2);

// These both point to the assembly from path1, so this is true
Console.WriteLine(assembly1.CodeBase == assembly2.CodeBase);

assembly1 = Assembly.LoadFile(path1);
assembly2 = Assembly.LoadFile(path2);

// These point to different assemblies now, so this is false
Console.WriteLine(assembly1.CodeBase == assembly2.CodeBase);

Изменить : чтобы ответить на вопросы, которые вы подняли в своем пересмотренном вопросе, вы определенно захотите прочитать Сюзанну Кук об идентичности сборки .

Существует множество правил, регулирующих загрузку сборок, и некоторые из них связаны с тем, как они разрешают зависимости - если ваша AssemblyA зависит от AssemblyB, где .NET должна искать AssemblyB? В глобальном кэше сборок, в том же каталоге, в котором он нашел AssemblyA, или в другом месте? Более того, если он находит несколько копий этой сборки, как ему выбирать, какую из них использовать?

LoadFromимеет один набор правил, а LoadFileдругой набор правил. Трудно вообразить множество причин для использования LoadFile, но если вам нужно было использовать отражение на разных копиях одной и той же сборки, оно есть для вас.

Джефф Стернал
источник
2
CodeBase - это то же самое, что и Identity?
Xaisoft
Нет, я просто использовал CodeBase здесь как произвольное свойство сборки, чтобы проиллюстрировать, что второй экземпляр Assembly указывал на «неправильный» файл (в первом примере). Я дополняю свой ответ более подробной информацией.
Джефф Стернал,
1
Это немного проясняет, но как path1 и path2 указывают на разные копии одной и той же сборки на диске при использовании LoadFrom и при использовании LoadFile, path1 и path2 указывают на разные сборки. Каков пример того, что будет path1 и path2? Спасибо за терпеливость.
Xaisoft
Почему вы проверяете две строковые ссылки на равенство значений string.Compare(x, y) == 0? Думаю, ты хочешь x == yтуда? Если по непонятным причинам вам действительно нужна проверка равенства, зависящая от языка и региональных параметров, это будет более понятно string.Equals(x, y, StringComparison.CurrentCulture), например, написать .
Jeppe Stig Nielsen
@JeffSternal Ссылка на "Suzanne Cook on Assembly Identity" здесь, кажется, не работает ...
Мартин Верьянс,
61

Из блога Сюзанны Кук :

LoadFile против LoadFrom

Будьте осторожны - это не одно и то же.

LoadFrom () проходит через Fusion и может быть перенаправлен на другую сборку по другому пути, но с тем же идентификатором, если он уже загружен в контекст LoadFrom.

LoadFile () вообще не связывается через Fusion - загрузчик просто выполняет * и загружает именно то, что запросил вызывающий. Он не использует контексты Load или LoadFrom.

Итак, LoadFrom () обычно дает вам то, что вы просили, но не обязательно. LoadFile () предназначена для тех, кто действительно хочет именно того, что требуется. (* Однако, начиная с версии 2, политика будет применяться как к LoadFrom (), так и к LoadFile (), поэтому LoadFile () не обязательно будет именно тем, что было запрошено. Кроме того, начиная с версии 2, если сборка с ее идентификатором находится в GAC, вместо этого будет использоваться копия GAC. Используйте ReflectionOnlyLoadFrom (), чтобы загрузить именно то, что вы хотите - но обратите внимание, что сборки, загруженные таким образом, не могут быть выполнены.)

LoadFile () имеет загвоздку. Поскольку он не использует контекст привязки, его зависимости не обнаруживаются автоматически в его каталоге. Если они недоступны в контексте загрузки, вам придется подписаться на событие AssemblyResolve, чтобы выполнить привязку к ним.

Смотрите здесь .

Также см. Статью « Выбор связующего контекста» в том же блоге.

CraigTP
источник
Спасибо, я проверю блог, я обновил свой пост, добавив несколько вопросов по документации msdn.
Xaisoft
@Xaisoft - блог Сюзанны Кук снова приходит на помощь с ответом на идентификацию сборок. См. Blogs.msdn.com/suzcook/archive/2003/07/21/57232.aspx . По сути, это «отображаемое имя сборки», которое выглядит примерно так: «Система, Версия = 1.0.3300.0, Культура = нейтральный, PublicKeyToken = b77a5c561934e089», поэтому включает в себя как фактическое имя сборки, так и номер версии вместе с другой идентифицирующей информацией (например, PublicKeyToken и т. Д.).
CraigTP
1
Что она имеет в виду, когда говорит о Fusion?
Xaisoft
1
Действительно, Джефф попал в точку. См. Эту ссылку: grimes.demon.co.uk/workshops/fusionWS.htm, где вы найдете хороший учебник по подсистеме Fusion и ее технологии для загрузки сборок в .NET
CraigTP
1
Просто быстрое обновление, обратите внимание, что указанный выше URL-адрес (grimes.demon.co.uk/workshops/fusionWS.htm) больше не действителен и теперь перемещен по адресу
CraigTP
45

После долгих размышлений сегодня днем ​​я сам обнаружил разницу.

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

LoadFile (): загружена конкретная DLL, но не зависимости. Поэтому, когда был сделан первый вызов одной из этих DLL из библиотеки DLL, она вызвала исключение FileNotFoundException.

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

LordWilmore
источник
4
Это была моя проблема! Я получал FileNotFoundExceptionпри создании нового экземпляра объекта, определенного в сборке, на которую ссылается сборка, которую я только что загрузил .LoadFile. Изменение этого на, .LoadFromпохоже, решило проблему, но я не знал почему! Спасибо
Connell
1
Спасибо, у меня была такая же проблема.
Ivandro IG Jao
4

Примечание. Если одна сборка загружается с использованием пути 8.3, а затем пути, отличного от 8.3, они будут рассматриваться как разные сборки, даже если это одна и та же физическая библиотека DLL.

Грегг ДеМастерс
источник
0

одно отличие, которое я заметил:

Assembly.LoadFile - загружает сборку в другой домен приложения с ограниченными правами пользователя (принцип различия). такие операции, как серилизация / десерилизация, не могут быть выполнены.

Assembly.LoadFrom - загружает сборку в один и тот же домен приложения с одинаковыми правами пользователя (тот же принцип).

Лалита
источник
3
Это не так. Что заставляет вас поверить, что Assembly.LoadFile загружает сборку в другой домен приложения?
Sven Mawby
0

В моем случае мне просто нужно было просто удалить кеш приложения ASP, расположенный @ C:\Windows\Microsoft.NET\Framework\[asp version]\Temporary ASP.NET Files. Он перестраивается при первом запуске сайта. Обязательно сначала остановите IIS.

Надеюсь, это поможет кому-то так же, как и мне.

Дэвид Рот
источник