2015-03-18 27 views
8

Napisałem funkcję, która akceptuje typ klasy (T) i typ interfejsu (I) i zwraca interfejs (I) do obiektu (T). Oto kod.Używanie Generics do tworzenia obiektu z interfejsem

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; 

Funkcja działa zgodnie z oczekiwaniami bez wycieków pamięci lub innych niepożądanych.

Czy istnieją inne sposoby osiągnięcia tego samego rezultatu?

+5

nie jestem pewien, że ten pytanie jest tutaj odpowiednie. Być może recenzja kodu byłaby lepszą stroną. Twoje ostateczne pytanie jest z pewnością oparte na opiniach. Pierwsze dwa pytania. 1. Tak, to jest OK. 2. Nie, żadnych problemów. –

+0

Przeformułuj ostatnie pytanie do "Czy istnieją inne sposoby osiągnięcia tego samego wyniku?" –

+0

@LURD - Przeformułowałem pytanie – norgepaul

Odpowiedz

14

W tym kodzie występuje błąd. Obsługa zniszczy instancję obiektu, jeśli obsługuje ona IUnknown, ale nie interfejs, o który pytasz.

Proste demonstracji:

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. 

najlepiej umieścić IInterface lub IUnknown jako dodatkowe ograniczenie do T.

Lub upewnij się, że nie niszczysz już zniszczonej instancji.

Chyba że chcesz wspierać dynamiczny QueryInterface implementacje (gdzie klasa nie implementuje interfejsu ale QueryInterface powraca IT) Chciałbym iść z Supports rozmowy na klasy:

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

Dobry połów Stefan. – norgepaul