상속, 집계, 포함
상속이라는 개념을 통해 .NET Framework에서 COM을 다시 사용할 수 있습니다. COM 형식은 기본 클래스로 상속에 참여할 수 있습니다. 다음과 같은 경우 상속, 집계 또는 포함 모델을 사용합니다.
모델 |
용도 |
---|---|
상속 |
관리되는 개체를 외부 개체로 노출 |
집계 |
수정 작업 없이 외부 개체가 다른 개체의 인터페이스 구현을 노출할 수 있음 |
포함 |
외부 개체가 내부 개체의 동작을 수정할 수 있음 |
상속
관리되는 인터페이스가 COM에 노출되는 경우 이 인터페이스는 항상 IUnknown 또는 IDispatch를 확장합니다. 인터페이스가 관리되는 쪽의 다른 인터페이스에서 상속되는 경우에도 마찬가지입니다. 관리되는 클래스에 대해 생성되는 클래스 인터페이스 소개에도 같은 규칙이 적용됩니다.
.NET Framework는 다시 사용할 수 있도록 하기 위해 구현 상속을 추가하여 COM 모델을 확장합니다. 관리되는 형식은 COM coclass에서 직접 또는 간접적으로 파생될 수 있으며, 특히 런타임에서 생성되는 RCW에서 파생될 수 있습니다. 파생 형식은 관리 코드에서 구현되는 메서드와 속성뿐만 아니라 COM 개체의 모든 메서드와 속성을 노출할 수 있습니다. 결과 개체의 일부는 관리 코드에서 구현되고 나머지 일부는 비관리 코드에서 구현됩니다.
기본 클래스로 한정하려면 coclass는 다음 조건을 만족해야 합니다.
메타데이터로 정의해야 합니다.
생성할 수 있어야 합니다.
집계가 가능해야 합니다(COM 개념).
관리되는 형식은 coclass 한정을 위해 RCW를 확장하고 기본 개체에서 제공하는 메서드를 재정의할 수 있습니다. 메서드를 재정의하려면 인터페이스의 모든 기본 메서드를 재정의해야 합니다.
관리되는 형식은 관리되는 기본 개체에서 상속되는 것과 동일한 방식으로 RCW에서 상속됩니다. 다음 코드 예제의 경우 관리되는 Catapult 클래스는 COM 형식 AcmeLib.Slingshot에서 파생됩니다.
#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 개체는 메타데이터를 .NET 어셈블리로 가져온 다음 다른 클래스 내에서 이 형식의 데이터 멤버를 선언하여 COM 개체를 포함할 수 있습니다. 일반적인 COM 포함을 사용하는 경우 고유의 인터페이스 구현에서 COM 개체의 인터페이스를 호출할 수 있지만 포함된 개체는 클래스 외부에 노출되지 않습니다. 포함은 집계 개념보다 간단합니다. 일반적으로 외부 개체가 내부 개체의 동작을 수정해야 하는 경우 포함을 사용합니다. 이렇게 하려면 외부 개체에서 해당 생성자에 내부 개체의 인스턴스를 만든 다음 필요에 따라 내부 개체에 호출을 위임하면 됩니다. 외부 개체는 위임할 호출과 직접 처리할 호출을 선택할 수 있습니다. 런타임에는 포함을 지원하기 위해 개체에 적용되는 특수 요구 사항이 없습니다.
또한 COM 개체는 .NET 개체를 포함할 수 있습니다. COM 개체의 클라이언트에 대한 동작은 포함된 개체가 다른 COM 개체인 경우와 정확히 일치합니다.