2013-02-18 9 views
9

Potrzebuję interfejsu implementującego klasę bez liczenia odwołań. Wykonałem następujące czynności:Przesyłanie obiektu do typu interfejsu bez TInterfacedObject jako klasy podstawowej

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; 

Brak liczenia odwołań działa dobrze. Ale moim problemem jest to, że nie mogę rzucić TMyClass do IMyInterface użyciu as operatora:

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

jestem daną

[DCC Error] E2015 Operator nie dotyczy tego typu argumentu

problem znika, gdy TMyClass wywodzi się z - tzn. mogę wykonywać takie casting bez błędu kompilatora. Oczywiście nie chcę używać TInterfacedObject jako klasy bazowej, ponieważ spowodowałoby to zliczenie odwołania do klasy. Dlaczego takie odrzucanie jest niedozwolone i jak można go obejść?

+0

Możesz mieć lepsze wyniki, dodając identyfikator GUID do deklaracji interfejsu. Dodaj nową linię po linii '= interface' i naciśnij Ctrl-Shft-G. 'as',' GetInterface' i 'supports' etc muszą być w stanie zidentyfikować interfejs GUID do pracy. –

+0

Nie przeczytałeś dokładnie mojego wpisu. kiedy wywodzę się z TInterfacedObject, działa. GUID nie ma tu nic do roboty. Potrzebujesz GUID tylko do pracy z COM. –

+0

Hmm, która wersja Delphi? –

Odpowiedz

14

Powodem, dla którego nie można używać kodu as w kodzie, jest to, że klasa nie podaje jawnie listy IInterface na liście obsługiwanych interfejsów. Mimo że interfejs pochodzi od IInterface, chyba że faktycznie wymienisz ten interfejs, twoja klasa go nie obsługuje.

Tak, trywialny fix jest zadeklarować swoją klasę tak:

TMyClass = class(TObject, IInterface, IMyInterface) 

Powodem, że klasa musi wdrożyć IInterface jest to, co kompilator powołując się na w celu realizacji as obsady.

Inną kwestią, którą chciałbym uczynić, jest to, że zasadniczo należy unikać dziedziczenia interfejsu. Ogólnie rzecz biorąc nie ma to większego sensu. Jedną z zalet korzystania z interfejsów jest to, że jesteś wolny od pojedynczego ograniczenia dziedziczenia związanego z dziedziczeniem implementacji.

Ale w każdym przypadku, wszystkie interfejsy Delphi automatically inherit from IInterface, więc w twoim przypadku nie ma sensu tego określać. Chciałbym zadeklarować swój interfejs tak:

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

Szerzej należy dążyć, aby nie używać dziedziczenia z interfejsów. Przyjmując takie podejście, zachęcamy do mniejszego sprzężenia, co prowadzi do większej elastyczności.

+0

Dziedziczenie interfejsu to ** nie ** dziedziczenie implementacji. Również każdy interfejs w Delphi pochodzi z 'IInterface'. Ostatnie zdanie jest niejasne. – kludg

+0

@Serg Dziedziczenie interfejsu to ** nie ** dziedziczenie implementacji jest dokładnie tym, co próbuję zrobić. Spróbuję to wyjaśnić. –

+1

Dzięki za wyjaśnienie. Teraz uważam to za jasne i oczywiste :) –