2013-02-18 3 views
9

Ho bisogno di un'interfaccia di implementazione di classe senza il conteggio dei riferimenti. Ho fatto quanto segue:Lancio dell'oggetto al tipo di interfaccia senza TInterfacedObject come classe base

IMyInterface = interface(IInterface) 
     ['{B84904DF-9E8A-46E0-98E4-498BF03C2819}'] 
     procedure InterfaceMethod; 
    end; 

    TMyClass = class(TObject, IMyInterface) 
    protected 
     function _AddRef: Integer;stdcall; 
     function _Release: Integer;stdcall; 
     function QueryInterface(const IID: TGUID; out Obj): HResult;stdcall; 
    public 
     procedure InterfaceMethod; 
    end; 

    procedure TMyClass.InterfaceMethod; 
    begin 
     ShowMessage('The Method'); 
    end; 

    function TMyClass.QueryInterface(const IID: TGUID; out Obj): HResult; 
    begin 
     if GetInterface(IID, Obj) then 
      Result := 0 
     else 
      Result := E_NOINTERFACE; 
    end; 

    function TMyClass._AddRef: Integer; 
    begin 
     Result := -1; 
    end; 

    function TMyClass._Release: Integer; 
    begin 
     Result := -1; 
    end; 

La mancanza di conteggio dei riferimenti funziona correttamente. Ma la mia preoccupazione è che non posso lanciare TMyClass-IMyInterface utilizzando as operatore:

var 
    MyI: IMyInterface; 
begin 
    MyI := TMyClass.Create as IMyInterface; 

mi viene data

[DCC errore] E2015 Operatore non applicabile a questo tipo di operando

Il il problema scompare quando TMyClass deriva da TInterfacedObject, ovvero posso eseguire tale operazione senza errore del compilatore. Ovviamente non voglio usare TInterfacedObject come una classe base in quanto renderebbe contato il riferimento alla mia classe. Perché questo casting non è consentito e come si potrebbe aggirarlo?

+0

È possibile ottenere risultati migliori aggiungendo un GUID alla dichiarazione dell'interfaccia. Aggiungi una nuova riga dopo la riga '= interface' e premi Ctrl-Shft-G. 'as',' GetInterface' e 'supports' ecc devono essere in grado di identificare l'interfaccia tramite GUID per funzionare. –

+0

Non hai letto attentamente il mio post. quando provengo da TInterfacedObject funziona. GUID non ha nulla da fare qui. È necessario GUID solo per operare con COM. –

+0

Hmm, quale versione di Delphi? –

risposta

14

Il motivo per cui non è possibile utilizzare as nel codice è che la classe non elenca esplicitamente IInterface nell'elenco delle interfacce supportate. Anche se la tua interfaccia deriva da IInterface, a meno che tu non elenchi effettivamente quell'interfaccia, la tua classe non la supporta.

Quindi, la correzione banale è quello di dichiarare la classe in questo modo:

TMyClass = class(TObject, IInterface, IMyInterface) 

La ragione per cui la classe deve implementare IInterface è questo è ciò che il compilatore si basa su al fine di attuare il as cast.

L'altro punto che vorrei fare è che, in generale, si dovrebbe evitare di usare l'ereditarietà dell'interfaccia. Nel complesso serve poco. Uno dei vantaggi dell'utilizzo delle interfacce è che non si è vincolati dal vincolo di ereditarietà singolo associato all'ereditarietà dell'implementazione.

Ma in ogni caso, tutte le interfacce Delphi automatically inherit from IInterface così nel tuo caso non ha senso specificarlo. Vorrei dichiarare l'interfaccia come questa:

IMyInterface = interface 
    ['{B84904DF-9E8A-46E0-98E4-498BF03C2819}'] 
    procedure InterfaceMethod; 
end; 

Più in generale si dovrebbe sforzarsi di non utilizzare l'ereditarietà con le interfacce. Adottando questo approccio incoraggerete meno accoppiamenti e ciò porterà a una maggiore flessibilità.

+0

L'ereditarietà dell'interfaccia è ** non ** l'ereditarietà dell'implementazione. Anche qualsiasi interfaccia in Delphi è derivata da "IInterface". L'ultima frase non è chiara. – kludg

+0

@Serg L'ereditarietà dell'interfaccia è ** non ** l'ereditarietà dell'implementazione è esattamente il punto che sto cercando di fare. Cercherò di chiarire. –

+1

Grazie per la spiegazione. Ora lo trovo chiaro ed ovvio :) –

Problemi correlati