Не зная конкретных деталей, я бы использовал интерфейсы , чтобы смешать подключаемые компоненты / модули. Требуется, чтобы каждый подключаемый модуль реализовывал интерфейс - скажем, IPluginComponent или любой другой, имеющий смысл. (На самом деле, для реализации интерфейса требуется только тот компонент, который должен взаимодействовать или взаимодействовать.) Как только все модули загружены, хост-приложение может запускать методы или события на компонентах.
Лично мне нравится держать вещи управляемыми данными и максимально простыми; поэтому я мог бы предпочесть «двухфазный» проход через модули. Это упрощает зависимости между модулями. Таким образом, на первом этапе, когда все компоненты загружены, хост-приложение запускает метод « ContributeSharedData (Context ctx) », где каждый компонент устанавливает любые значения в общем контексте. (Это также может называться " Init (ctx) ".) Контекст может быть таким же простым, как коллекция пар имя-значение, например, Модуль B говорит * coll ["ModuleB_Installed"] = true *, или он может добавить себя в список модулей, или ... возможности безграничны. Контекстом может быть любой класс или структура, необходимые для совместной работы этих компонентов.
Следующий этап - если требуется - будет для компонентов / модулей для настройки на основе общего контекста. Таким образом, хост может проходить через все модули, поддерживающие общий интерфейс, и запускать метод или событие «Настроить». Затем ModuleA, например, может посмотреть в контексте и увидеть, что ModuleB установлен, и соответствующим образом настроить его интерфейс.
Если интерфейс не имеет смысла для вашей ситуации, вы можете использовать любой способ предоставления общих данных общим способом в общее местоположение, например, обмен сообщениями или другие общие классы.
Надеюсь, это поможет!