Зачем использовать делегаты при использовании удаленного взаимодействия объектов MarshalByRefObj?
Мое приложение поддерживает плагины, у меня есть класс Core (MarshalByRefObj), который плагины должны наследовать, и этот класс предлагает различные функциональные возможности. Теперь мой вопрос: когда этот класс создается в главном домене приложения и передается плагину в другом домене приложения, какая польза от использования делегатов в таком сценарии:
public class Core : MarshalByRefObject
{
public void DoSomething()
{
MyMainApp.Delegate1("SomeMethod", "Test");
}
}
Итак, как вы можете видеть, мой основной класс вызывает метод делегата в MyMainApp. Я мог бы просто сделать MyMainApp.SomeMethod("test")
вместо.
Однако во многих примерах в Интернете о том, как работает система удаленного взаимодействия и плагинов, каждый, похоже, использует делегатов. Есть ли какая-то конкретная причина для этого? Может ли кто-нибудь дать мне более практический пример того, почему?
2 ответа
Большую часть времени элементы управления в пользовательском интерфейсе создаются основным потоком, если вы не намеренно создаете их в другом потоке. Вот важный бит: ТОЛЬКО поток, создавший элемент управления, может получить доступ к этому элементу управления.
Если вы позвоните DoSomething
напрямую и код в DoSomething
хочет взаимодействовать с элементом управления пользовательского интерфейса, это не будет разрешено, и вы получите исключение. MyMainApp.Delegate1("DoSomething"
эквивалентно: Пожалуйста, выполните указанный метод в главном потоке. Теперь он может получить доступ к элементам управления пользовательского интерфейса.
Есть и другие причины, но это самое важное, что нужно помнить. Смотрите MSDN для получения дополнительной информации.
Одним из преимуществ будет то, что информация передается MyMainApp.Delegate1
сериализуется для переноса из домена приложения плагина в домен главного приложения. Delegate1
метод выполнит DoSomething
в основном домене. Они не разделяют память (поэтому прямой доступ к экземплярам объекта невозможен). Таким образом, вы можете динамически запускать методы на других доменах приложений. И если это делается с помощью отражения, плагин может запускать не перечисленные методы.
Я бы предпочел не использовать этот тип конструкции, потому что нет никакой проверки во время компиляции при вызове методов. Я бы предпочел использовать интерфейсы, которые есть в спутниковых сборках. (для предотвращения main-appdomain получает ссылку на / загрузку сборки плагина, поэтому он больше не может быть выгружен)
Другое дело: если вы позвоните MyMainApp.SomeMethod("test")
непосредственно. Это означает, что плагин должен знать определение загрузчика плагинов. Это означает, что вы получаете жесткую связь (из плагина) с "родительским" приложением (версией). Что делает всю структуру плагина "бесполезной". Вы можете исправить это, реализовав ISupportSomeMethod
интерфейс на MyMainApp, который определен в спутниковой сборке, используемой обоими приложениями mainapp и плагином. Если ваш MyMainApp не реализует ISupportSomeMethod
Интерфейс, плагин не совместим с этой программой. Таким образом, ваш MyMainApp
может поддерживать несколько структур плагинов.
В этом случае вы предпочитаете структуру событий. Потому что дочерний объект хочет вызвать метод своего родителя. Жаль, что вызовы междоменных событий бесполезны, потому что ваш основной модуль загрузит сборку, и ее нельзя будет выгружать. Вы можете написать прокси-класс для этого.