Как загрузить сборку во время выполнения до события AssemblyResolve? - PullRequest
10 голосов
/ 21 июля 2009

На самом деле я пытался реализовать какие-то «статически связанные» сборки в своем решении. Поэтому я попробовал следующее:

  • Добавление ссылки на мою сборку с помощью CopyLocal = false
  • Добавление самого файла .dll в мое решение с помощью команды «Добавить как ссылку»
  • Добавление самого DLL-файла к моим ресурсам с помощью «Добавить ресурс» - «Добавить существующий файл»
  • Добавление некоторого типа из моей сборки в Form1 как private MyObject temp = new MyObject();

После этих шагов я получил FileNotFoundException, как и ожидалось. Итак, давайте попробуем загрузить сборку в AssemblyResolveEvent с помощью этого быстрого хака

AppDomain.CurrentDomain.AssemblyResolve += (sender, e) =>
    {
        Assembly MyAssembly = AppDomain.CurrentDomain.Load(Properties.Resources.ExternalAssembly);
        return MyAssembly;
    };

Так что это работает! Я могу загрузить свою сборку из файла ресурсов в AssemblyResolveEvent. Но это событие происходит только в том случае, если оно не может найти мою сборку где-либо еще. Но как я могу загрузить свою сборку до того, как .Net попытается найти разные места ??

В связи с фактами из Проверка ранее ссылающихся сборок Я думал, что можно было бы заранее загрузить сборку в домен, и это будет сделано.

Я пробовал это в program.cs, используя следующий метод Main ()

static void Main()
{
    LoadMyAssemblies();
    AppDomain.CurrentDomain.AssemblyResolve += (sender, e) => LoadMyAssemblies();
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new Form1());
}

private static Assembly LoadMyAssemblies()
{
    Assembly result = AppDomain.CurrentDomain.Load(Properties.Resources.MyStaticAssembly);
    return result;
}

Но он все еще сталкивается с ResolveEventHandler. И что еще лучше, если я снова загружу сборку и взгляну на AppDomain.CurrentDomain.GetAssemblies () , я вижу, что моя сборка загружается дважды !!

Так что любая идея, почему моя загруженная сборка не будет учтена при загрузке до события AssemblyResolve ?? С помощью отладчика я также возвратил нулевое значение, когда вызов поступил из AssemblyResolve, но в этом случае я получил FileNotFoundException как в начале.

Ответы [ 2 ]

3 голосов
/ 22 июля 2009

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

Событие AssemblyResolve всегда запускается в тот момент, когда Binder решает, что он искал все возможные местоположения (которые можно найти в этом приложении) и не может найти совпадение.

Напрашивается оригинальный вопрос: зачем вам статически связывать управляемые сборки? Прочитайте эту ветку, чтобы обсудить это Преимущества статических ссылок

Я пойду дальше и отвечу на часть о том, как избежать попадания в событие AssemblyResolve. 1) Поместите сборку в GAC. Что касается Binder, GAC всегда побеждает. 2) Поместите вашу сборку в путь зондирования и убедитесь, что Binder ее подхватывает (подробнее об этом смотрите в статье «Как среда выполнения находит сборки» в MSDN).

3 голосов
/ 21 июля 2009

На тот случай, если вы не знали, есть инструмент под названием ILMerge от MS Research, который объединяет сборки в один файл.

Также вы можете создавать многофайловые сборки с помощью инструмента Assembly Linker .

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

...