2010-06-02 16 views
6

Sto memorizzando piccole interfacce da un intervallo di oggetti in un unico "negozio" di TInterfaceList con l'intenzione di offrire un elenco di tipi di interfaccia specifici all'utente finale, quindi ogni l'interfaccia esporrà una funzione 'GetName' ma tutti gli altri metodi sono unici per quel tipo di interfaccia. Per esempio qui ci sono due interfacce:Come memorizzare e localizzare più tipi di interfaccia all'interno di Delphi TInterfaceList

IBase = interface 
    //---------------------------------------- 
    function GetName : string; 
    //---------------------------------------- 
    end; 

    IMeasureTemperature = interface(IBase) 
    //------------------------------------ 
    function MeasureTemperature : double; 
    //---------------------------------------- 
    end; 

    IMeasureHumidity = interface(IBase) 
    //---------------------------------------- 
    function MeasureHumidity: double; 
    //---------------------------------------- 
    end; 

ho messo alcune di queste interfacce in un unico TInterfaceList e poi mi piacerebbe scorrere la lista per un tipo di interfaccia specifica (ad esempio 'IMeasureTemperature') la costruzione di un altro elenco di puntatori agli oggetti che esportano tali interfacce. Non voglio fare supposizioni sulle posizioni di quegli oggetti, alcuni potrebbero esportare più di un tipo di interfaccia. So che potrei fare questo con una gerarchia di classi con qualcosa di simile:

If FList[I] is TMeasureTemperature then .. 

ma mi piacerebbe fare qualcosa simliar con un tipo di interfaccia, è possibile?

+1

Si potrebbe voler chiarire se il primo elenco contiene l'interfaccia effettiva * tipi * o riferimenti alle istanze * oggetto * che implementano tali interfacce. Sembra che tutte le persone che hanno risposto qui finora abbiano assunto quest'ultimo mentre leggevo la tua domanda per parlare del primo ... poi di nuovo non puoi memorizzare i * tipi di interfaccia * in un 'TInterfaceList' ... quindi probabilmente ho torto ... –

risposta

2

Immagino che potrebbe soddisfare le vostre esigenze.

function InterfaceRefIsInterface(Intf : IUnknown; ExpectedIntf : TGUID) : Boolean; 
var vReference : IUnknown; 
begin 
    if Supports(Intf, ExpectedIntf, vReference) then 
    Result := Intf = vReference 
    else 
    Result := False; 
end; 

io non sono sicuro di come la funzione si comporterà quando INTF e ExpectedIntf eredita gli uni dagli altri, ma questo restituisce true nel caso INTF è una corrispondenza esatta di ExpectedIntf.

Nell'esempio, IMeasureHumidity non restituirà true su IMeasureTemperature, ma non sono sicuro di come reagirà a IBase. Secondo i test preliminari, restituirà anche FALSE su IBase.

+0

Tranne quando 'ExpectedIntf' è' IUnknown', non vi è alcuna garanzia che 'Intf' sia uguale a' vReference'. Le [regole per l'implementazione di QueryInterface] (http://msdn.microsoft.com/en-us/library/ms686590.aspx) promettono che una chiamata a QueryInterface avrà esito positivo, ma non richiedono che venga restituito alcun particolare puntatore all'interfaccia. –

+0

Dal proprio collegamento "una chiamata a QueryInterface con IID_IUnknown deve sempre restituire lo stesso valore del puntatore fisico" e "Qualsiasi interfaccia deve essere in grado di interrogare qualsiasi altra interfaccia su un oggetto". Non sono sicuro di quale regola si riferisce che farebbe fallire questo. –

+0

Funziona bene e fa esattamente quello che speravo, anche se dovrei guardarlo molto attentamente per vedere cosa sta facendo! Non ci sarà mai un caso in cui l'interfaccia IBase ereditata sarebbe passata. Grazie molto. –

6

Proprio utilizzo di supporti, in questo modo:

var 
    oMTIntf: IMeasureTemperature; 
... 
    If Supports(FList[I], IMeasureTemperature, oMTIntf) then .. 
+0

@ da-soft: bel suggerimento ma non riesce quando una singola classe esporta due interfacce diverse - "Supports" restituisce true in quel caso per ciascuno. Ho bisogno di un modo per identificare il tipo reale dell'interfaccia. –

+0

Mi dispiace, sembra che mi sia mancato il tuo punto chiave. Hai bisogno di ottenere oggetti dall'interfaccia o di ottenere un'interfaccia dall'interfaccia? Se prima, quindi http://www.malcolmgroves.com/blog/?p=500. Se secondo, poi come ho scritto (ho modificato il mio messaggio). –

+0

@Brian: Perché è un problema? Se una delle due interfacce discende dall'altro, controlla la classe discendente prima della classe genitore. E se non lo fanno, allora entrambi i risultati sono ugualmente validi. –

2

è possibile utilizzare la funzione di Supports in SysUtils, sono abbastanza sicuro (a meno che non li provi sulla memoria non inizializzate) e avete solo bisogno di una variabile di destinazione del esatto tipo di interfaccia si tenta di trasmettere a:


procedure DoSomethingInList(AList: IInterfaceList;); 
var 
    i: Integer; 
    liItem: IInterface; 
    liMeasureTemp: IMeasureTemperature; 
    liMeasureHumi: IMeasureHumidity; 
begin 
    AList.Lock; 
    try 
    for i := 0 to AList.Count - 1 do 
    begin 
     liItem := AList[i]; 
     if Supports(liItem, IMeasureTemperature, liMeasureTemp) then 
     //... liMeasureTemp.MeasureTemperature ... 
     else if Supports(liItem, IMeasureHumidity, liMeasureHumi) then 
     //... liMeasureHumi.MeasureHumidity ... 
     else 
     //... 
    end; 
    finally 
    AList.Unlock; 
    end; 
end; 
Problemi correlati