Share via


Einführung in die Klassenschnittstelle

Die Klassenschnittstelle, die nicht explizit in verwaltetem Code definiert ist, macht alle öffentlichen Methoden, Eigenschaften, Felder und Ereignisse verfügbar, die wiederum explizit für das .NET-Objekt verfügbar gemacht sind. Sie kann eine duale oder eine auf Dispatch beschränkte Schnittstelle sein. Die Klassenschnittstelle erhält den Namen der .NET-Klasse, dem ein Unterstrich vorangestellt ist. Die Klasse Mammal z. B. hat die Klassenschnittstelle _Mammal.

Auch bei abgeleiteten Klassen macht die Klassenschnittstelle alle öffentlichen Methoden, Eigenschaften und Felder der Basisklasse verfügbar. Auch die abgeleitete Klasse macht eine Klassenschnittstelle für jede Basisklasse verfügbar. Wenn beispielsweise die Mammal-Klasse zur MammalSuperclass-Klasse erweitert wird und diese wiederum zu System.Object, zeigt das .NET-Objekt COM-Clients gegenüber drei Klassenschnittstellen an, die _Mammal, _MammalSuperclass und _Object genannt werden.

Betrachten Sie beispielsweise die folgende .NET-Klasse:

' 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();
}

Der COM-Client kann einen Zeiger auf die Klassenschnittstelle _Mammal erhalten. Diese wird in der vom Tool Type Library Exporter-Tool (Tlbexp.exe) generierten Typbibliothek beschrieben. Würde die Mammal-Klasse eine oder mehrere Schnittstellen implementieren, würden diese Schnittstellen unterhalb der Co-Klasse angezeigt werden.

   [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;
   }

Die Generierung der Klassenschnittstelle ist optional. Standardmäßig generiert COM-Interop eine auf Dispatch beschränkte Schnittstelle für jede Klasse, die in eine Typbibliothek exportiert wird. Sie können die automatische Erstellung dieser Schnittstelle verhindern oder abändern, indem Sie der Klasse das ClassInterfaceAttribute zuweisen. Obwohl die Klassenschnittstelle das Verfügbarmachen von verwalteten Klassen für COM erleichtern kann, sind ihre Verwendungsmöglichkeiten begrenzt.

WarnhinweisVorsicht

Wenn Sie die Klassenschnittstelle verwenden, anstatt explizit eine eigene zu definieren, kann dies das zukünftige Versioning der verwalteten Klasse erschweren.Lesen Sie zuerst die folgenden Richtlinien, bevor Sie die Klassenschnittstelle verwenden.

Definieren Sie eine explizite Schnittstelle zur Verwendung durch COM-Clients, anstatt die Klassenschnittstelle zu generieren.

Da durch COM-Interop automatisch eine Klassenschnittstelle generiert wird, können nachträgliche Änderungen der Klasse das Layout der Klassenschnittstelle verändern, die durch Common Language Runtime verfügbar gemacht wird. COM-Clients sind in der Regel nicht auf Veränderungen im Layout der Schnittstelle eingestellt und brechen deshalb ab, wenn das Memberlayout der Klasse verändert wurde.

Diese Richtlinie unterstreicht die Tatsache, dass gegenüber COM-Clients verfügbar gemachte Schnittstellen nicht verändert werden dürfen. Um das Risiko von Abbrüchen durch unbeabsichtigte Veränderung des Schnittstellenlayouts seitens der COM-Clients zu minimieren, sollten Sie durch explizites Definieren von Schnittstellen alle Klassenveränderungen vom Schnittstellenlayout isolieren.

Verwenden Sie ClassInterfaceAttribute, um die automatische Generierung der Klassenschnittstelle abzukoppeln, und implementieren Sie eine explizite Schnittstelle für die Klasse, wie im folgenden Codefragment dargestellt:

<ClassInterface(ClassInterfaceType.None)>Public Class LoanApp
    Implements IExplicit
    Sub M() Implements IExplicit.M
…
End Class
[ClassInterface(ClassInterfaceType.None)]
public class LoanApp : IExplicit {
    void M();
}

Der ClassInterfaceType.None-Wert verhindert die Generierung der Klassenschnittstelle während des Exports der Klassenmetadaten in eine Typbibliothek. Im vorherigen Beispiel erhalten die COM-Clients nur über die IExplicit-Schnittstelle Zugriff auf die LoanApp-Klasse.

Vermeiden Sie das Zwischenspeichern von Dispatchbezeichnern (DispIds).

Die Verwendung der Klassenschnittstelle ist eine zulässige Option für Skriptclients, Microsoft Visual Basic 6.0-Clients oder beliebige spät gebundene Clients, welche die DispIds von Schnittstellenmembern nicht zwischenspeichern. DispIds identifizieren Schnittstellenmember, um spätes Binden zu ermöglichen.

Bei der Klassenschnittstelle basiert die Generierung von DispIds auf der Position des Members in der Schnittstelle. Wenn Sie die Reihenfolge der Member ändern und die Klasse in eine Typbibliothek exportieren, werden die in der Klassenschnittstelle generierten DispIds ebenfalls verändert.

Um bei Verwendung der Klassenschnittstelle den Abbruch seitens spät gebundener COM-Clients zu verhindern, wenden Sie das ClassInterfaceAttribute mit dem ClassInterfaceType.AutoDispatch-Wert an. Dieser Wert implementiert eine auf Dispatch beschränkte Klassenschnittstelle, unterdrückt jedoch die Schnittstellenbeschreibung der Typbibliothek. Ohne eine Schnittstellenbeschreibung sind Clients nicht in der Lage, DispIds zur Kompilierungszeit zwischenzuspeichern. Obwohl dies der Standardtyp für die Klassenschnittstelle ist, können Sie den Attributwert explizit anwenden.

<ClassInterface(ClassInterfaceType.AutoDispatch)> Public Class LoanApp
    Implements IAnother
    Sub M() Implements IAnother.M
…
End Class
[ClassInterface(ClassInterfaceType.AutoDispatch]
public class LoanApp : IAnother {
    void M();
}

COM-Clients können IDispatch.GetIdsOfNames aufrufen, um den DispId eines Schnittstellenmembers zur Laufzeit zu erhalten. Übergeben Sie den zurückgegebenen DispId als Argument an IDispatch.Invoke, um eine Methode für die Schnittstelle aufzurufen.

Beschränken Sie die Verwendung der dualen Schnittstellenoption für die Klassenschnittstelle.

Duale Schnittstellen ermöglichen COM-Clients frühe und späte Bindung an Schnittstellenmember. In der Entwurfs- und Testphase kann es hilfreich sein, die Klassenschnittstelle als duale Schnittstelle einzurichten. Bei einer verwalteten Klasse (und ihren Basisklassen), die niemals verändert wird, ist diese Option ebenfalls zulässig. In allen anderen Fällen jedoch ist die Einstellung der Klassenschnittstelle als duale Schnittstelle zu vermeiden.

Eine automatisch generierte duale Schnittstelle kann in seltenen Fällen angemessen sein, führt aber in der Regel zu versionsbedingter Komplexität. Wenn COM-Clients beispielsweise die Klassenschnittstelle einer abgeleiteten Klasse verwenden, ist die Wahrscheinlichkeit eines Abbruchs bei Veränderungen der Basisklasse sehr hoch. Wird die Basisklasse von einem Drittanbieter bereitgestellt, haben Sie keine Kontrolle mehr über das Layout der Klassenschnittstelle. Darüber hinaus stellt eine duale Schnittstelle (ClassInterface.AutoDual) im Gegensatz zu einer auf Dispatch beschränkten eine Beschreibung der Klassenschnittstelle in der exportierten Typbibliothek bereit. Durch diese Beschreibung werden spät gebundene Clients veranlasst, DispIds zur Laufzeit zwischenzuspeichern.

Siehe auch

Referenz

ClassInterfaceAttribute

Konzepte

COM Callable Wrapper (CCW)

Qualifizieren von .NET-Typen für die Interoperation