使用Generics创建接口对象

时间:2015-03-18 09:58:29

标签: delphi generics interface delphi-xe7

我编写了一个接受类类型(T)和接口类型(I)的函数,并将一个接口(I)返回给对象(T)。这是代码。

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;

该函数按预期工作,没有内存泄漏或其他不受欢迎的内容。

还有其他方法可以达到相同的效果吗?

1 个答案:

答案 0 :(得分:14)

此代码中存在错误。如果支持IUnknown而不支持您要求的接口,则支持将销毁您的对象实例。

简单演示:

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.

最好将IInterfaceIUnknown作为T的附加约束。

或者确保你没有销毁已经被破坏的实例。

除非你想支持动态QueryInterface实现(类没有实现接口但QueryInterface返回它),我会在类上调用Supports

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;