2015-03-18 13 views
8

Ho scritto una funzione che accetta un tipo di classe (T) e un tipo di interfaccia (I) e restituisce un'interfaccia (I) all'oggetto (T). Ecco il codice.Uso di Generics per creare un oggetto interfacciato

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; 

La funzione funziona come previsto, senza perdite di memoria o altri indesiderabili.

Ci sono altri modi per ottenere lo stesso risultato?

+5

non sono sicuro che questo la domanda è appropriata qui. Forse la revisione del codice sarebbe un sito migliore. La tua domanda finale è certamente basata sull'opinione pubblica. Prime due domande. 1. Sì, questo è OK. 2. No, nessun problema. –

+0

Riformula l'ultima domanda in "ci sono altri modi per ottenere lo stesso risultato?" –

+0

@LURD - Ho riformulato la domanda – norgepaul

risposta

14

C'è un bug in questo codice. I supporti distruggeranno l'istanza dell'oggetto se supporta IUnknown ma non l'interfaccia richiesta.

semplice dimostrazione:

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. 

Meglio mettere IInterface o IUnknown come ulteriore vincolo per T.

Oppure assicurati di non distruggere un'istanza già distrutta.

A meno che non si desidera supportare dinamica QueryInterface implementazioni (in cui la classe non implementa l'interfaccia, ma QueryInterface restituisce) vorrei andare con un Supports chiamata sulla classe:

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

Buona presa Stefan. – norgepaul

Problemi correlati