클래스 인터페이스 소개
업데이트: 2007년 11월
관리 코드에서 명시적으로 정의되지 않은 클래스 인터페이스는 .NET 개체에서 명시적으로 노출된 모든 공용 메서드, 속성, 필드 및 이벤트를 노출하는 인터페이스입니다. 이 인터페이스에는 이중 또는 디스패치 전용 인터페이스가 있습니다. 클래스 인터페이스의 이름은 .NET 클래스의 이름 앞에 밑줄을 붙입니다. 예를 들어 Mammal 클래스의 경우 클래스 인터페이스는 _Mammal입니다.
파생 클래스의 경우 클래스 인터페이스는 또한 기본 클래스의 모든 공용 메서드, 속성, 필드를 노출합니다. 또한 파생 클래스는 각 기본 클래스의 클래스 인터페이스도 노출합니다. 예를 들어 Mammal 클래스가 MammalSuperclass 클래스를 확장하고 MammalSuperclass 클래스가 System.Object를 확장하는 경우 .NET 개체는 _Mammal, _MammalSuperclass 및 _Object라는 세 가지 클래스 인터페이스를 COM 클라이언트에 노출합니다.
다음 .NET 클래스 예제를 참조하십시오.
' Applies the ClassInterfaceAttribute to set the interface to dual.
<ClassInterface(ClassInterfaceType.AutoDual)> _
' Implicitly extends System.Object.
Public Class Mammal
Sub Eat()
Sub Breathe()
Sub Sleep()
End Class
// Applies the ClassInterfaceAttribute to set the interface to dual.
[ClassInterface(ClassInterfaceType.AutoDual)]
// Implicitly extends System.Object.
public class Mammal
{
void Eat();
void Breathe():
void Sleep();
}
COM 클라이언트는 이름이 _Mammal인 클래스 인터페이스에 대한 포인터를 얻을 수 있으며 이는 형식 라이브러리 내보내기(Tlbexp.exe) 도구에서 생성하는 형식 라이브러리에서 설명합니다. Mammal 클래스에서 하나 이상의 인터페이스를 구현한 경우 해당 인터페이스가 coclass 아래에 나타납니다.
[odl, uuid(…), hidden, dual, nonextensible, oleautomation]
interface _Mammal : IDispatch
{
[id(0x00000000), propget] HRESULT ToString([out, retval] BSTR*
pRetVal);
[id(0x60020001)] HRESULT Equals([in] VARIANT obj, [out, retval]
VARIANT_BOOL* pRetVal);
[id(0x60020002)] HRESULT GetHashCode([out, retval] short* pRetVal);
[id(0x60020003)] HRESULT GetType([out, retval] _Type** pRetVal);
[id(0x6002000d)] HRESULT Eat();
[id(0x6002000e)] HRESULT Breathe();
[id(0x6002000f)] HRESULT Sleep();
}
[uuid(…)]
coclass Mammal
{
[default] interface _Mammal;
}
클래스 인터페이스 생성은 선택 사항입니다. 기본적으로 COM interop는 형식 라이브러리로 내보내는 각 클래스에 대해 디스패치 전용 인터페이스를 생성합니다. ClassInterfaceAttribute를 클래스에 적용하여 이 인터페이스가 자동으로 생성되지 않게 하거나 이를 수정할 수 있습니다. 클래스 인터페이스를 통해 관리되는 클래스를 COM에 노출하는 작업이 쉬워지지만 사용하는 데 제한이 있습니다.
주의: |
---|
사용자가 직접 명시적으로 정의하는 대신 클래스 인터페이스를 사용하면 관리되는 클래스의 이후 버전 관리가 복잡해질 수 있습니다. 클래스 인터페이스를 사용하기 전에 다음 지침을 자세히 읽어 보십시오. |
클래스 인터페이스를 생성하는 대신 사용할 COM 클라이언트의 명시적 인터페이스를 정의합니다.
COM interop는 클래스 인터페이스를 자동으로 생성하므로 이후 클래스의 버전 변경으로 인해 공용 언어 런타임에 의해 노출된 클래스 인터페이스의 레이아웃이 변경될 수 있습니다. COM 클라이언트는 일반적으로 인터페이스의 레이아웃 변경 내용을 처리할 준비가 되어 있지 않으므로 클래스의 멤버 레이아웃을 변경하면 중단됩니다.
이 지침은 COM 클라이언트에 노출된 인터페이스를 변경할 수 없다는 개념을 보충합니다. 인터페이스 레이아웃의 순서를 실수로 바꾸어 COM 클라이언트가 중단되는 경우를 줄이려면 인터페이스를 명시적으로 정의하여 클래스의 모든 변경 내용을 인터페이스 레이아웃에서 분리시킵니다.
다음 코드와 같이 ClassInterfaceAttribute를 사용하여 클래스 인터페이스 자동 생성을 해제하고 클래스의 명시적 인터페이스를 구현합니다.
<ClassInterface(ClassInterfaceType.None)>Public Class LoanApp
Implements IExplicit
Sub M() Implements IExplicit.M
…
End Class
[ClassInterface(ClassInterfaceType.None)]
public class LoanApp : IExplicit {
void M();
}
ClassInterfaceType.None 값은 클래스 메타데이터를 형식 라이브러리로 내보낼 때 클래스 인터페이스가 생성되지 않게 합니다. 위의 예제에서 COM 클라이언트는 IExplicit 인터페이스를 통해서만 LoanApp 클래스에 액세스할 수 있습니다.
디스패치 식별자(DispId) 캐싱을 방지합니다.
클래스 인터페이스는 Microsoft Visual Basic 6.0 클라이언트와 같은 스크립팅된 클라이언트 또는 인터페이스 멤버의 DispId를 캐싱하지 않는 런타임에 바인딩된 클라이언트에서 선택적으로 사용할 수 있습니다. DispId는 런타임에 바인딩이 가능하도록 인터페이스 멤버를 식별합니다.
클래스 인터페이스의 경우 DispId는 인터페이스의 멤버 위치에 따라 생성됩니다. 멤버 순서를 변경하고 클래스를 형식 라이브러리로 내보내면 클래스 인터페이스에서 생성되는 DispId가 변경됩니다.
클래스 인터페이스를 사용하는 경우 런타임에 바인딩된 COM 클라이언트가 중단되지 않게 하려면 ClassInterfaceType.AutoDispatch 값을 사용하여 ClassInterfaceAttribute를 적용합니다. 이 값은 디스패치 전용 클래스 인터페이스를 구현하지만 형식 라이브러리에서 인터페이스 설명을 생략합니다. 인터페이스 설명이 없는 경우 클라이언트는 컴파일 타임에 DispId를 캐싱할 수 없습니다. 이는 클래스 인터페이스에 대한 기본 인터페이스 형식이지만 특성 값을 명시적으로 적용할 수 있습니다.
<ClassInterface(ClassInterfaceType.AutoDispatch)> Public Class LoanApp
Implements IAnother
Sub M() Implements IAnother.M
…
End Class
[ClassInterface(ClassInterfaceType.AutoDispatch]
public class LoanApp : IAnother {
void M();
}
런타임에 인터페이스 멤버의 DispId를 얻기 위해 COM 클라이언트에서 IDispatch.GetIdsOfNames를 호출할 수 있습니다. 인터페이스에 대해 메서드를 호출하려면 반환된 DispId를 IDispatch.Invoke에 인수로 전달합니다.
클래스 인터페이스에 대한 이중 인터페이스 옵션 사용을 제한합니다.
이중 인터페이스를 사용하면 COM 클라이언트에 의해 인터페이스 멤버에 초기 및 런타임에 바인딩이 가능합니다. 디자인 타임에서 그리고 테스트하는 동안 클래스 인터페이스를 이중으로 설정하는 것이 유용하다는 것을 알 수 있습니다. 수정되지 않는 관리되는 클래스와 해당 기본 클래스의 경우에도 이 옵션을 사용할 수 있습니다. 다른 모든 경우에 대해서는 클래스 인터페이스를 이중으로 설정하지 마십시오.
자동으로 생성되는 이중 인터페이스가 적절한 경우도 있지만 대부분의 경우 이중 인터페이스를 사용하면 버전과 관련하여 복잡한 문제가 일어납니다. 예를 들어 파생 클래스의 클래스 인터페이스를 사용하는 COM 클라이언트는 기본 클래스를 변경하면 손쉽게 중단될 수 있습니다. 타사에서 기본 클래스를 제공하는 경우에는 클래스 인터페이스의 레이아웃을 제어할 수 없습니다. 또한 디스패치 전용 인터페이스와 달리 이중 인터페이스(ClassInterface.AutoDual)는 내보낸 형식 라이브러리의 클래스 인터페이스 설명을 제공합니다. 이를 사용하면 런타임에 바인딩된 클라이언트가 런타임에 DispId를 캐싱할 수 있게 됩니다.