Наследование, агрегирование и вложенность

Повторное использование COM в среде .NET Framework осуществляется путем наследования. COM-типы могут участвовать в наследовании в качестве базового класса. Модели наследования, агрегирования и вложенности используются в следующих обстоятельствах.

Модель

Использование

Наследование

Предоставление доступа к управляемому объекту как к внешнему объекту.

Агрегат

Разрешение внешнему объекту предоставлять доступ к реализации интерфейса другим объектом без изменений.

Вложенность

Разрешение внешнему объекту изменять поведение внутреннего объекта.

Наследование

Если для COM предоставляется доступ к управляемым интерфейсам, они всегда расширяют интерфейс IUnknown или IDispatch, даже если интерфейс унаследован из другого интерфейса на управляемой стороне. Это же правило применимо и к интерфейсам классов, создаваемых для управляемых классов.

Среда .NET Framework расширяет модель COM для повторного использования, добавляя наследование реализации. Управляемые типы могут быть прямо или косвенно производными от компонентного COM-класса напрямую или косвенно. В частности, они могут быть производными от вызываемой оболочки времени выполнения, созданной средой выполнения. Производный тип может предоставить доступ ко всем методам и свойствам COM-объекта, а также к методам и свойствам, реализованным в управляемом коде. Получившийся объект частично реализуется в управляемом коде, а частично — в неуправляемом коде.

Чтобы иметь возможность считаться базовым классом, компонентный класс должен удовлетворять следующим требованиям:

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

Управляемый тип наследуется из вызываемой оболочки времени выполнения точно так же, как из управляемого базового объекта. В следующем примере кода управляемый класс Catapult является производным от AcmeLib.Slingshot, COM-типа.

#using "AcmeLib.dll"    // Provides definition of Slingshot.

__gc class Catapult : public AcmeLib.Slingshot  // Extends the COM type.
{
    // Delegates to base implementation.
    Load() { //… };  
   
    Fire()               
    {
        // Engages in some behavior before delegating to the base 
        // implementation.
        Slingshot::Fire();
    }

    // The Aim method needs to be overridden.
    Aim() { //… }         
}
Catapult *cp = new Catapult();

// Calls derived implementation.
cp->Load();
// Calls base implementation.
cp->Aim();
// Calls derived which delegates to base.
cp->Fire();

Агрегат

Чтобы предоставить доступ к интерфейсам одного COM-класса, как будто они реализованы во втором COM-классе, второй класс агрегирует первый класс. COM-объект может агрегировать объект .NET, и в этом случае все интерфейсы объекта, в том числе и соответствующий интерфейс класса, доступны через внешний объект. Внутренний объект .NET делегирует вызовы методов IUnknown управляющему методу IUnknown.

Агрегирование — это процесс немного более сложный, чем вложенность (описываемая в следующем разделе). Агрегирование обычно используется, чтобы позволить внешнему объекту предоставлять доступ к реализации интерфейса другим объектом без изменения. Все управляемые объекты автоматически поддерживают агрегирование в COM-стиле, при которой управляемый объект используется в качестве внутреннего объекта. Чтобы агрегировать управляемый объект, неуправляемый внешний объект создает управляемый внутренний объект, вызывая метод CoCreateInstance, а затем передавая интерфейс IUnknown внешнего объекта как параметр OuterUnknown. Если внешний интерфейс IUnknown передается управляемому объекту во время создания, управляемый объект кэширует интерфейс и использует его следующим образом:

  • Внешний объект старается сохранить неделегируемый интерфейс IUnknown внутреннего интерфейса IUnknown. Неделегируемый интерфейс IUnknown ведет себя, как обычный интерфейс IUnknown, то есть он успешно работает, если объект реализует интерфейс, и выдает сбой в противном случае. Неделегируемый интерфейс IUnknown не пересылает вызов внешнему объекту.

  • Если у внутреннего объекта запрашивается интерфейс, который он не поддерживает, внутренний объект делегирует вызов интерфейсу IUnknown внешнего объекта.

  • Все вызовы методов QueryInterface, AddRef и Releaseвнутреннего объекта делегируются интерфейсу IUnknown внешнего объекта.

Эти три процедуры делают возможным агрегирование любого управляемого объекта. Этот тип связи при агрегировании позволяет использовать COM-объект, частично реализованный в управляемом коде (внутренняя часть) и частично — в неуправляемом коде (внешняя часть).

Вложенность

Объект .NET может содержать COM-объект, импортируя метаданные в сборку .NET, а затем объявляя элемент данных этого типа в другом классе. Как и в случае с обычной вложенностью COM, разработчик может вызывать интерфейсы COM-объекта в собственных реализациях интерфейса, но доступ к вложенному объекту вне класса не предоставляется. Вложенность проще агрегирования. Вложенность обычно используется, когда внешнему объекту нужно изменить поведение внутреннего объекта. Для этого внешний объект просто создает экземпляр внутреннего объекта в своем конструкторе и по мере необходимости делегирует вызовы внутреннему объекту. Внешний объект может выбирать, какие вызовы делегировать, а какие обрабатывать непосредственно. Среда выполнения не предъявляет никаких особых требований к объектам для поддержки вложенности.

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

См. также

Основные понятия

Предоставление клиентам .NET Framework доступа к COM-компонентам

Предоставление COM-клиентам доступа к компонентам .NET Framework

Другие ресурсы

Расширенное COM-взаимодействие