Condividi tramite


Conversione dei membri esportati

In questo argomento viene descritto in che modo il processo di esportazione converte i seguenti membri:

  • Metodi

  • Proprietà

  • Eventi

Metodi

I client COM contano di chiamare i metodi passandovi come parametri tipi dati noti e prevedono di ricevere HRESULT. In ambiente .NET, invece, le classi non sono soggette a tali restrizioni sui tipi restituiti (e infatti non utilizzano HRESULT).

Al fine di accomodare le esigenze di entrambi i modelli, ogni metodo di un tipo gestito ha una firma .NET e una firma COM implicita. Le due firme sono solitamente molto diverse. I client .NET interagiscono con il server utilizzando la firma .NET, mentre (anche contemporaneamente) i client COM interagiscono con il server utilizzando la firma COM. Il server implementa il metodo con la firma .NET e il servizio di marshalling del runtime è responsabile di fornire uno stub con la firma COM che delega la chiamata al metodo gestito.

Traduzione dell'HRESULT

Una firma gestita viene convertita in una firma non gestita modificando il valore restituito gestito in un parametro [out, retval] e modificando il tipo del valore restituito non gestito in HRESULT. Il metodo DoSomething potrebbe ad esempio avere la seguente firma:

Firma gestita

short DoSomething(short i);

Firma non gestita

HRESULT DoSomething([in] short i, [out, retval] short *rv);

Si noti che la firma COM restituisce un HRESULT e ha un parametro aggiuntivo out per il valore restituito. Il valore restituito dall'implementazione gestita è sempre causa dell'aggiunta di un parametro [out, retval] alla fine della firma non gestita, mentre la firma non gestita restituisce sempre un HRESULT. Se il metodo gestito restituisce un void, il runtime omette il parametro [out, retval]. Esempio:

Firma gestita

void DoSomething(short i);

Firma non gestita

HRESULT DoSomething([in] short i);

In alcune circostanze, è preferibile non modificare la firma gestita. A tal fine, è possibile utilizzare PreserveSigAttribute. Esempio:

Firma gestita

[PreserveSig] short DoSomething(short i);

Firma non gestita

short DoSomething ([in] short i);

La disponibilità di due firme distinte permette ad entrambi i client COM e .NET di utilizzare la classe senza particolari difficoltà. I client COM e .NET possono inoltre utilizzare la classe .NET contemporaneamente. L'autore della classe implementa solo la firma gestita. Tlbexp.exe (o un'API equivalente) provvede a esportare la firma in una libreria dei tipi generata per la classe.

Metodi di overload

Benché .NET supporti l'overload dei metodi, l'interfaccia IDispatch si basa unicamente sul nome del metodo per l'associazione, anziché sulla firma completa. Essa non è pertanto in grado di supportare l'overload dei metodi. Al fine di consentirvi l'accesso, Tlbexp.exe decora tuttavia il nome di ciascun metodo in overload di un tipo aggiungendovi un numero ordinale, così da renderlo univoco.

Le seguenti firme gestita e non gestita mostrano l'inclusione di numeri:

Firma gestita

interface INew {
public:
    void DoSomething();
    void DoSomething(short s);
    void DoSomething(short l);
    void DoSomething(float f);
    void DoSomething(double d);
}

Firma non gestita

interface INew {
    void DoSomething();
    void DoSomething_2(short s);
    void DoSomething_3(short l);
    void DoSomething_4(float f);
    void DoSomething_5(double d);
}

La firma COM dei metodi presenta un solo metodo DoSomething seguito da una serie di metodi DoSomething_x, dove x comincia da 2 e viene incrementato ad ogni forma di overload del metodo. Si noti che alcuni metodi in overload possono essere ereditati da un tipo base. Non c'è comunque garanzia che i metodi in overload conserveranno lo stesso numero al cambiare della versione del tipo.

Benché i client .NET possano utilizzare la forma in overload del metodo, i client COM devono accedere ai metodi decorati. I visualizzatori oggetto riportano tutte le forme del metodo decorato con la relativa firma, così da permettere la scelta del metodo corretto. I client ad associazione tardiva possono anche ottenere il DispID di ogni metodo di overload chiamando IDispatch::GetIdsOfNames e passandogli il nome decorato.

Proprietà

Le classi e le interfacce gestite possono avere proprietà. Una proprietà gestita appartiene a un tipo dati specifico e può essere associata a un metodo per la lettura (get) e a un metodo per l'impostazione (set) del proprio valore. Tali metodi sono definiti separatamente come qualsiasi altro metodo. Nell'esempio di codice che segue viene illustrata un'interfaccia contenente una proprietà Height. Le classi che implementano l'interfaccia devono fornire un metodo get un metodo set per la proprietà.

    interface IMammal {
 
    IMammal Mother{get;set;}
    IMammal Father{get;set;}
    int     Height{get;set;}
    int     Weight{get;set;}

    }

    class Human : IMammal
    {
        int weight;
        int height;
        IMammal father;
        IMammal mother;

        public IMammal Mother { get { return mother; } set { mother = value; } }
        public IMammal Father { get { return father; } set { father = value; } }
        public int Height { get { return height; } set { height = value; } }
        public int Weight { get { return weight; } set { weight = value; } }
    }

Durante l'esportazione, Tlbexp.exe converte il metodo set della proprietà in [propput] e il metodo get in [propget]. Il metodo della proprietà in COM resta uguale a quello della proprietà gestita. Questa regola presenta le seguenti eccezioni:

  • Se il tipo della proprietà, esclusi i tipi valore, è una classe o un'interfaccia, il metodo set diviene un [propputref], conferendo ai parametri un ulteriore livello di riferimenti indiretti.

  • Se la proprietà non dispone di metodi get o set, Tlbexp.exe la omette dalla libreria dei tipi.

Anche i campi gestiti, come le proprietà, vengono esportati nella libreria dei tipi. Il servizio di marshalling del runtime genera automaticamente i metodi get e set per tutti i campi pubblici. Durante il processo di conversione, Tlbexp.exe genera una funzione [propput] (o [propputref]) e una funzione [propget] per ciascun campo, come illustrato nella rappresentazione di libreria dei tipi riportata di seguito.

Rappresentazione di libreria dei tipi

interface IMammal : IDispatch {
         [propget]    HRESULT Mother([out, retval] IMammal** pRetVal);
         [propputref] HRESULT Mother([in] IMammal* pRetVal);
         [propget]    HRESULT Father([out, retval] IMammal** pRetVal);
         [propputref] HRESULT Father([in] IMammal* pRetVal);
         [propget]    HRESULT Height([out, retval] long* pRetVal);
         [propput]    HRESULT Height([in] long pRetVal);
         [propget]    HRESULT Weight([out, retval] long* pRetVal);
         [propput]    HRESULT Weight([in] long pRetVal);
         [propget]    HRESULT Age([out, retval] long* pRetVal);
         [propput]    HRESULT Age([in] long pRetVal);    
};

Eventi

Se non si ha familiarità con il modello eventi dell'interoperabilità COM, vedere Eventi gestiti e non gestiti. I tipi gestiti implementano gli eventi utilizzando un modello eventi basato sui delegati. Ad esempio, l'interfaccia Class1Events, illustrata nell'esempio di codice che segue, genera l'evento Click.

    Public Delegate Sub ClickDelegate()
    <GuidAttribute("1A585C4D-3371-48dc-AF8A-AFFECC1B0967"), _
    InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)>

    Public Interface Class1Event
        Sub Click ()
    End Interface
<ComSourceInterfaces("Class1Event, EventSrc")> _
    Public Class Class1
        Public Event Click As ClickDelegate
   End Class
    public delegate void Click();

    public interface Class1Event
    {
        void Click();
    }
   [ComSourceInterfaces("Class1Event, EventSrc")]
    public class Class1
    {
        public event ClickDelegate Click;
    }

Durante l'esportazione, Tlbexp.exe contrassegna l'interfaccia eventi come origine nella relativa coclasse. Come illustrato nella rappresentazione di libreria dei tipi riportata di seguito, l'interfaccia esportata ComClass1Events è contrassegnata come interfaccia di origine.

Rappresentazione di libreria dei tipi

    disinterface Class1Event {
        properties:
        methods:
        [id(0x60020000)]
        HRESULT Click();
    };

    coclass Class1
    {
    …
    [default, source] Class1Event;
    };

Vedere anche

Concetti

Conversione degli assembly esportati

Conversione dei moduli esportati

Conversione dei tipi esportati

Conversione dei parametri esportati

Altre risorse

Riepilogo della conversione da assembly a libreria dei tipi