Introduzione all'interfaccia della classe
Aggiornamento: novembre 2007
L'interfaccia della classe, che non è definita esplicitamente nel codice gestito, è un'interfaccia che espone tutte le proprietà, i campi, gli eventi e i metodi pubblici esplicitamente esposti dall'oggetto .NET. Tale interfaccia può essere duale o solo dispatch. L'interfaccia della classe riceve il nome dalla classe .NET stessa, preceduto da un carattere di sottolineatura. Per la classe Mammal, l'interfaccia della classe sarà ad esempio _Mammal.
Per le classi derivate, l'interfaccia della classe espone anche tutti i metodi, le proprietà e i campi pubblici della classe base. La classe derivata espone anche un'interfaccia della classe per ciascuna classe base. Se ad esempio la classe Mammal estende la classe MammalSuperclass, che a sua volta estende la classe System.Object, l'oggetto .NET esporrà ai client COM tre interfacce della classe denominate _Mammal, _MammalSuperclass e _Object.
Si consideri ad esempio la seguente classe .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();
}
Il client COM può ottenere un puntatore a un'interfaccia della classe denominata _Mammal, che è descritta nella libreria dei tipi generata dall'utilità di esportazione della libreria dei tipi (Tlbexp.exe). Se la classe Mammal implementa una o più interfacce, queste appariranno sotto la coclasse.
[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;
}
La generazione dell'interfaccia della classe è facoltativa. In base all'impostazione predefinita, l'interoperabilità COM genera un'interfaccia solo dispatch per ogni classe esportata in una libreria dei tipi. È possibile modificare o impedire la creazione automatica di questa interfaccia applicando alla classe l'oggetto ClassInterfaceAttribute. Benché l'interfaccia della classe possa semplificare l'esposizione di classi gestite a COM, gli usi che è possibile farne sono limitati.
Attenzione: |
---|
Utilizzare l'interfaccia della classe, anziché definire esplicitamente un'interfaccia personalizzata, può complicare il futuro controllo delle versioni della classe gestita. Prima di utilizzare l'interfaccia della classe, leggere le indicazioni riportate di seguito. |
Definire un'interfaccia esplicita per i client COM anziché generare l'interfaccia della classe.
Poiché l'interoperabilità COM genera l'interfaccia della classe automaticamente, le modifiche apportate alla classe dopo l'emissione di una versione possono alterare il layout dell'interfaccia della classe esposta da Common Language Runtime. Se si cambia il layout dei membri della classe, la maggior parte dei client COM, che solitamente non è in grado di gestire le modifiche al layout di un'interfaccia, cesserà di funzionare.
Queste indicazioni ribadiscono il concetto che le interfacce esposte ai client COM devono restare immodificabili. Per ridurre il rischio di compromettere il funzionamento dei client COM riordinando inavvertitamente il layout dell'interfaccia, separare tutte le modifiche alla classe dal layout dell'interfaccia definendo esplicitamente le interfacce.
Utilizzare ClassInterfaceAttribute per disattivare la generazione automatica dell'interfaccia della classe e implementare un'interfaccia esplicita per la classe, come illustrato nel seguente frammento di codice:
<ClassInterface(ClassInterfaceType.None)>Public Class LoanApp
Implements IExplicit
Sub M() Implements IExplicit.M
…
End Class
[ClassInterface(ClassInterfaceType.None)]
public class LoanApp : IExplicit {
void M();
}
Il valore ClassInterfaceType.None impedisce la generazione dell'interfaccia della classe quando i metadati della classe vengono esportati in una libreria dei tipi. Nel precedente esempio, i client COM possono accedere alla classe LoanApp solo tramite l'interfaccia IExplicit.
Evitare l'inserimento nella cache degli ID dispatch (o DispId).
L'utilizzo dell'interfaccia della classe è ammissibile per i client basati su script, i client Microsoft Visual Basic 6.0 o qualsiasi client ad associazione tardiva che non inserisce nella cache i DispId dei membri di interfaccia. I DispId identificano i membri di interfaccia per abilitare l'associazione tardiva.
Per l'interfaccia della classe, la generazione dei DispId è basata sulla posizione dei membri nell'interfaccia. Se si cambia l'ordine dei membri e si esporta la classe in una libreria dei tipi, si altereranno i DispId generati nell'interfaccia della classe.
Per evitare di compromettere il funzionamento dei client COM ad associazione tardiva quando si utilizza questa interfaccia, applicare ClassInterfaceAttribute con il valore ClassInterfaceType.AutoDispatch. Tale valore implementa un'interfaccia della classe solo dispatch, ma omette la descrizione dell'interfaccia dalla libreria dei tipi. Senza una descrizione dell'interfaccia, i client non potranno inserire i DispId nella cache in fase di compilazione. Benché questo sia il tipo di interfaccia predefinito per l'interfaccia della classe, è possibile applicare il valore dell'attributo in modo esplicito.
<ClassInterface(ClassInterfaceType.AutoDispatch)> Public Class LoanApp
Implements IAnother
Sub M() Implements IAnother.M
…
End Class
[ClassInterface(ClassInterfaceType.AutoDispatch]
public class LoanApp : IAnother {
void M();
}
Per ottenere il DispId di un membro di interfaccia in fase di esecuzione, i client COM possono chiamare IDispatch.GetIdsOfNames. Per richiamare un metodo sull'interfaccia, passare il DispId restituito come argomento a IDispatch.Invoke.
Non utilizzare l'opzione di interfaccia duale per l'interfaccia della classe.
Le interfacce duali permettono ai client COM di effettuare sia l'associazione anticipata che l'associazione tardiva ai membri di interfaccia. In fase di progettazione e durante il test, è possibile che si riveli utile impostare l'interfaccia della classe su duale. Per una classe gestita (e le relative classi base) che non verrà mai modificata, questa opzione è ammissibile. In tutti gli altri casi, è preferibile evitare di impostare l'interfaccia della classe su duale.
Un'interfaccia duale generata automaticamente può essere ammessa in alcuni casi meno comuni. Nella maggior parte dei casi essa creerà invece complicazioni in relazione alla gestione delle versioni. Ad esempio, il funzionamento dei client COM che utilizzano l'interfaccia della classe di una classe derivata verrà facilmente compromesso in conseguenza di modifiche della classe base. Quando la classe base è fornita da un altro produttore, il layout dell'interfaccia della classe sarà fuori del proprio controllo. Diversamente da un'interfaccia solo dispatch, un'interfaccia duale (ClassInterface.AutoDual) fornisce inoltre una descrizione dell'interfaccia della classe nella libreria dei tipi esportata. Tale descrizione invita i client ad associazione tardiva a inserire nella cache i DispId in fase di esecuzione.
Vedere anche
Concetti
Qualificazione di tipi .NET per l'interoperabilità