Динамически загружаемая сборка: почему этот код работает? - PullRequest
0 голосов
/ 20 ноября 2011

В моей ситуации есть три компонента: Consumer класс, IExposedIface интерфейс и Exposed класс, реализующий IExposedIfaceConsumer, и Exposed статически связаны с IExposedIface, но Consumer не имеет ссылки на время компиляции на Exposed.

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

Пока мне кажется, что есть два варианта предоставления IExposedIface сборки для Exposed сборка.

  1. Наличие IExposedIface.dll только в Consumer 's bin директории и обработка AppDomain.AssemblyResolve события для AppDomain, в котором я нахожусьсоздание экземпляра Exposed

  2. Наличие IExposedIface.dll как в каталоге Consumer bin , так и в стороне каждого Exposed.dll.

Теперь рассмотрим, что я строю Exposed против этого IExposedIface:

public interface IExposedIface
{
    string SaySomething();    
}

, и я строю Consumer против этого IExposedIface:

public interface IExposedIface
{
    string SaySomething();
    string SaySomethingDifferent();
}

В первом случае исключение

Исключение: Метод 'SaySomethingDifferent' в типе 'Exposed.Exposed' из сборки 'Exposed, Version = 1.0.0.0, Culture= нейтральный, PublicKeyToken = null ' не имеет реализации .

выбрасывается в тот момент, когда я вызываю appDomain.CreateInstanceAndUnwrap(...), чтобы создать экземпляр Exposed iВ только что созданном AppDomain .

Мне это кажется разумным.

Но во втором случае appDomain.CreateInstanceAndUnwrap(...) проходит нормально, и я могу без проблем вызвать 'SaySomething () 'метод для извлеченного объекта.Исключение

Метод 'SaySomethingDifferent' не найден в интерфейсе / типе 'IExposedIface.IExposedIface, IExposedIface, Версия = 2.0.0.0, Culture = нейтральный, PublicKeyToken = null'.

выдается только тогда, когда я на самом деле звоню SaySomethingDifferent() в Consumer.

Я был очень удивлен, что во втором случае CLR позволил мне зайти так далеко ...Может ли кто-нибудь объяснить, почему это возможно?

1 Ответ

0 голосов
/ 20 ноября 2011
  1. Случай № 1 означает, что Exposed.dll связывается с неверной версией IExposedIface.dll - загрузчик метаданных может обнаружить это при загрузке сборок, поскольку он находит не реализованный метод интерфейса.

  2. Случай № 2 (вероятно) означает, что у вас есть правильная версия каждого IExposedIface.dll, кроме каждого Exposed.dll, чтобы каждая сборка могла загружаться в своем собственном домене приложений. Однако интерфейс AppDomain A отличается от интерфейса AppDomain B, что является проблемой только тогда, когда вызов фактически пересекает границу AppDomain.

Я бы посоветовал не пробовать эти игры с двоичной совместимостью, а скорее делать правильное управление версиями (т.е. создать новый интерфейс с новыми методами, наследуя от старого интерфейса, поэтому новая версия IExposedIface.dll действительно обратная совместимость). Что-то еще действительно трудно отладить, потому что вы можете случайно закончить загрузкой обеих версий IExposedIface.dll, если они доступны для окон, и тогда у вас есть две версии типа в AppDomain не вызывает никаких проблем;)

...