Предоставление класса.NET (который имеет события) для COM
Я хочу открыть класс.NET для COM. Это довольно просто:
- Я создаю интерфейс, в котором я определяю членов этого класса, который должен быть ComVisible
- Я сам определяю DispId для этих членов
- Я определяю, что интерфейс должен быть
ComVisible
- Я назначаю
Guid
к этому интерфейсу - Я создаю класс, который реализует этот интерфейс
Ничего страшного. Это все работает. Но теперь мой вопрос таков: у меня есть несколько событий в этом классе, которые я тоже хочу представить COM.
Это также не должно иметь большого значения, но, когда я смотрю на некоторые примеры (например, код, сгенерированный MS ComInterop), я вижу, что события объявляются в отдельном интерфейсе. То есть: класс, который должен быть ComVisible
, реализует 2 интерфейса:
- один интерфейс, который определяет обычные методы и свойства, которые должны быть
ComVisible
- другой интерфейс, который определяет события, которые должны быть
ComVisible
,
Теперь мой вопрос: почему это так? Что является причиной этого?
Почему ComVisible
события, определенные в другом интерфейсе, и почему они просто не определены в интерфейсе, который содержит методы и свойства, которые должны быть ComVisible
?
В чем причина этого?
2 ответа
Это связано с тем, как работают события COM. COM не имеет ни малейшего представления, что такое делегат, и поэтому его события реализуются с использованием интерфейса обратного вызова. Объект, который хочет получать события, реализует интерфейс событий, передает его отправителю (ваш код), и отправитель вызывает для него методы. Таким образом, интерфейс событий является отдельным, потому что вы не хотите, чтобы кто-то, заинтересованный в ваших событиях, должен был реализовать остальную часть вашего интерфейса.
За кулисами интерфейсы событий управляются с помощью "точек подключения", которые позволяют получателям подключать свои интерфейсы обратного вызова к отправителю. Эта реализация требует набора COM-интерфейсов (IConnectionPoint, IConnectionPointContainer, IEnumConnectionPoints, IEnumConnections) и некоторого утомительного обслуживания. Если вы реализуете события COM, например, в родном C++, вам нужно позаботиться об этих интерфейсах. К счастью, как программист.NET вам не нужно их реализовывать, поскольку.NET сделает это за вас.
События всегда определялись в отдельном интерфейсе. Это не уникально для интерфейсов COM, реализованных в.NET, но для всех интерфейсов COM. На мой взгляд, интерфейс представляет собой набор методов и свойств, но методы в интерфейсе событий не вызываются, как ни один из них. Они вызываются сервером, а не клиентом, что не соответствует поведению обычных методов. Таким образом, реализовав эти методы в отдельном интерфейсе, вы можете отделить функции, которые могут быть вызваны сервером, от методов, которые могут быть вызваны клиентом. Клиент не должен иметь возможность вызывать методы событий. Необходимо реализовать интерфейс на объекте, который может вызывать сервер. Кроме того, клиент не должен реализовывать интерфейсы, которые уже реализованы на сервере. Он должен вызывать существующую реализацию тех интерфейсов, которые реализованы на сервере. Самый простой способ сделать это - предоставить клиенту один интерфейс для реализации событий, а другой - сервер, который клиент может вызывать для уже реализованных функций.