2015-03-18 15 views
8

Ich habe eine Funktion geschrieben, die einen Klassentyp (T) und einen Schnittstellentyp (I) akzeptiert und eine Schnittstelle (I) an das Objekt (T) zurückgibt. Hier ist der Code.Verwenden von Generics zum Erstellen eines verknüpften Objekts

interface 

function CreateObjectInterface<T: Class, constructor; I: IInterface>(
    out AObject: TObject): I; 

...

implementation 

function TORM.CreateObjectInterface<T, I>(out AObject: TObject): I; 
begin 
    AObject := T.Create; 

    if not Supports(AObject, GetTypeData(TypeInfo(I))^.Guid, Result) then 
    begin 
    AObject.Free; 
    AObject := nil; 

    raise EORMUnsupportedInterface.CreateFmt(
     'Object class "%s" does not support interface "%s"', 
     [AObject.ClassName, GUIDToString(GetTypeData(TypeInfo(I))^.GUID)] 
    ); 
    end; 
end; 

Die Funktion arbeitet wie ohne Speicherlecks oder andere unerwünschte Personen erwartet.

Gibt es andere Möglichkeiten, um das gleiche Ergebnis zu erzielen?

+5

Ich bin nicht sicher, dass diese Frage ist hier angebracht. Vielleicht wäre Code Review eine bessere Seite. Ihre letzte Frage ist sicherlich meinungsbezogen. Erste zwei Fragen. 1. Ja, das ist OK. 2. Nein, keine Probleme. –

+0

Die letzte Frage umformulieren: "Gibt es andere Möglichkeiten, dasselbe Ergebnis zu erzielen?" –

+0

@LURD - Ich habe die Frage umformuliert – norgepaul

Antwort

14

In diesem Code ist ein Fehler enthalten. Unterstützungen zerstören Ihre Objektinstanz, wenn sie IUnknown unterstützt, aber nicht die Schnittstelle, nach der Sie fragen.

Einfache Demonstration:

type 
    IFoo = interface 
    ['{32D3BE83-61A0-4227-BA48-2376C29F5F54}'] 
    end; 

var 
    o: TObject; 
    i: IFoo; 
begin 
    i := TORM.CreateObjectInterface<TInterfacedObject, IFoo>(o); // <- boom, invalid pointer 
end. 

Beste IInterface oder IUnknown als zusätzliche Einschränkung zu T setzen.

Oder stellen Sie sicher, dass Sie eine bereits zerstörte Instanz nicht zerstören.

Sofern Sie QueryInterface Implementierungen dynamisch unterstützen wollen (wo die Klasse nicht implementiert die Schnittstelle aber QueryInterface kehrt es) ich mit einem Supports Anruf auf die Klasse gehen würde:

function TORM.CreateObjectInterface<T, I>(out AObject: TObject): I; 
begin 
    if not Supports(TClass(T), GetTypeData(TypeInfo(I))^.Guid) then 
    raise EORMUnsupportedInterface.CreateFmt(
     'Object class "%s" does not support interface "%s"', 
     [AObject.ClassName, GUIDToString(GetTypeData(TypeInfo(I))^.GUID)] 
    ); 

    AObject := T.Create; 
    Supports(AObject, GetTypeData(TypeInfo(I))^.Guid, Result); 
end; 
+0

Guter Fang Stefan. – norgepaul

Verwandte Themen