如何解决界面乱七八糟的问题

Wod*_*dzu 2 delphi interface delphi-2009

我一直在考虑将接口作为一种为不同的不相关类提供通用功能的方法.但是接口的属性 - "当RefCOunt降到零时释放一个对象"不允许我按照我的意愿工作.

例如:假设我有两个不同的类:TMyObject和TMyDifferentObject.他们都支持这个界面:

const
  IID_MyInterface: TGUID = '{4D91C27F-510D-4673-8773-5D0569DFD168}';

type
 IMyInterface = Interface(IInterface)
  ['{4D91C27F-510D-4673-8773-5D0569DFD168}']
  function GetID : Integer;
 end;

type
  TMyObject = class(TInterfacedObject, IMyInterface)
    function GetID: Integer;
  end;

function TMyObject.GetID: Integer;
begin
  Result := 1;
end;


type
  TMyDifferentObject = class(TInterfacedObject, IMyInterface)
    function GetID: Integer;
  end;

function TMyDifferentObject.GetID: Integer;
begin
  Result := 2;
end;
Run Code Online (Sandbox Code Playgroud)

现在,我想在我的程序中创建此类的实例,然后将这些实例传递给此方法:

procedure ShowObjectID(AObject: TObject);
var
  MyInterface: IMyInterface;
begin
  if Supports(AObject, IID_MyInterface, MyInterface) then
  begin
    ShowMessage(IntToStr(MyInterface.GetID));
  end;
end;  //Interface goes out of scope and AObject is freed but I still want to work with that object!
Run Code Online (Sandbox Code Playgroud)

这是一个例子.一般情况下,我想将对象的实例传递给某个过程并检查该对象是否支持接口,如果是,我想执行该接口的方法.但是当界面超出范围时,我不想完成该对象的工作.这该怎么做?

问候.

Mar*_*ema 8

您的问题可能源于您使用对象引用创建对象的事实:

var
  MyObject: TObject;
begin
  MyObject := TMyObject.Create;
  ShowMessage('Before ShowObjectID MyObject RefCount: ' + IntToStr(MyObject.RefCount));
  ShowObjectID(MyObject);
  ShowMessage('After ShowObjectID MyObject RefCount: ' + IntToStr(MyObject.RefCount));
end;
Run Code Online (Sandbox Code Playgroud)

这样做意味着创建后的RefCount为零.只要您需要,您也可以将对象分配给接口引用,

var
  MyObject: TMyObject;
  MyIntf: IMyInterface;
begin
  MyObject := TMyObject.Create;
  MyIntf := MyObject;
  ShowMessage('Before ShowObjectID MyObject RefCount: ' + IntToStr(MyObject.RefCount));
  ShowObjectID(MyObject);
  ShowMessage('After ShowObjectID MyObject RefCount: ' + IntToStr(MyObject.RefCount));
  MyIntf := nil;
  ShowMessage('After nilling the interface MyObject RefCount: ' + IntToStr(MyObject.RefCount));
end;
Run Code Online (Sandbox Code Playgroud)

或者像David在评论中建议的那样禁用引用计数.这实质上意味着声明自己的"TInterfacedObject"并实现三个IInterface方法:

function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
Run Code Online (Sandbox Code Playgroud)

本质是返回-1_AddRef和_Release.正如大卫所说:看看TComponent是如何做到的.当FVCLComObject为零时,只需要做它正在做的事情.