首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >调用TObject.GetInterface自由对象

调用TObject.GetInterface自由对象
EN

Stack Overflow用户
提问于 2012-09-10 03:41:13
回答 1查看 1.5K关注 0票数 2

我正在尝试执行下面这样的代码:

代码语言:javascript
复制
IFoo = Interface
   procedure DoFoo;
end;

TFoo = class (TInterfaceObject, IFoo)
  .....
   procedure DoFoo;
end;

TFoo2 = class (TInterfaceObject)
  ......
end;

TGenClass = class
  class function DoSomething<T: class, cronstructor>: T;
end;

class function TGenClass.DoSomething<T>: T;
var Obj: T;
    Foo: IFoo;
begin
   Obj := T.Cretae;
   if Obj.GetInterfaceEntry(IFoo) <> nil then 
   begin
     Obj.GetInterface(IFoo, Foo);
     Foo.DoFoo;
   end;
   result := Obj;
end; 
......
var f: TFoo;
    f2: TFoo2; 
begin
  f:= TGenClass.DoSomeThing<TFoo>;
  f2:= TGenClass.DoSomeThing<TFoo2>;
  f2.free;
  f.free;
end;

当我执行这段代码时,f.free会抛出一个异常,因为我想它已经是空闲的了,因为如果我注释下面这几行

代码语言:javascript
复制
Obj.GetInterface(IFoo, Foo);
Foo.DoFoo;

它起作用了。

?如何在没有自由对象的情况下执行IFoo接口?

谢谢。

添加:

谢谢大家。我明白。

我试着用同样的结果返回IFoo。我的问题是T不能是TInterfacedObject。我尝试转换的Java代码是:

代码语言:javascript
复制
public  void dataIterate(int recNo, ResultSet data) throws SQLException {

    try {

        Constructor c = itemClass.getDeclaredConstructor();
        c.setAccessible(true);
        Object item = c.newInstance();
        if (item instanceof CustomInitialize) ((CustomInitialize)item).initialize(data);
        else {

            if (metadata == null ) metadata = data.getMetaData();
            for (int i=1; i<= metadata.getColumnCount(); i++)
                assignProperty(itemClass, item, "set"+metadata.getColumnName(i).toLowerCase(), data.getObject(i));

        }
        add((E)item);

    } catch (Exception ex) {
        throw new SQLDataException(ex);
    }
   ..........

Delphi示例代码:

代码语言:javascript
复制
program Project4;

{$APPTYPE CONSOLE}

{$R*.res}

uses
   System.SysUtils,  System.Rtti;

type
  IFoo = Interface
     ['{F2D87AE6-1956-4B82-A28F-DC011C529849}']
     procedure DoFoo;
  end;

  TFoo = class (TInterfacedObject, IFoo)
  private
    FName: String;
  public
     procedure DoFoo;
     property Name: String Read FName write FName;
  end;

  TFoo2 = class (TObject)
  private
    FName: String;
  published
      property Name: String Read FName write FName;
  end;

TGenClass = class
  class function DoSomething<T: class, constructor>: T;
end;

class function TGenClass.DoSomething<T>: T;
var Obj: T;
    Foo: IFoo;
    Ap: TRttiProperty;
    Ctx: TRttiContext;
begin
   Obj := T.Create;
   if Obj.GetInterfaceEntry(IFoo) <> nil then
   begin
     Obj.GetInterface(IFoo, Foo);
     Foo.DoFoo;
   end;
   Ctx.GetType(TypeInfo(T)).GetProperty('Name').SetValue(TObject(Obj),'AName');
   result := Obj;
end;
{ TFoo }

procedure TFoo.DoFoo;
begin
  writeln('Foo executed.');
end;
var f: TFoo;
    f2:TFoo2;
begin
  try
    f:= TGenClass.DoSomeThing<TFoo>;
    f2:= TGenClass.DoSomeThing<TFoo2>;
    writeln(f2.Name);
    writeln(f.Name);   //<-- raise exception
    f.free;
    f2.Free;
    readln;

  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-09-10 03:45:53

让我们来看看这段代码:

代码语言:javascript
复制
class function TGenClass.DoSomething<T>: T;
var Obj: T;
    Foo: IFoo;
begin
   Obj := T.Create;
   if Obj.GetInterfaceEntry(IFoo) <> nil then 
   begin
     Obj.GetInterface(IFoo, Foo);
     Foo.DoFoo;
   end;
   result := Obj;
end; 

Obj := T.Create之后,对象的引用计数为零,因为还没有接口变量引用它。然后在Foo中调用GetInterface并获取一个接口引用。因此,对象现在的引用计数为1,然后函数返回,Foo超出作用域。这会将引用计数减少到0,因此对象会被释放。

使用TInterfacedObject时,必须始终保留接口变量。这样引用计数就可以管理对象的生命周期。在这种情况下,您有混合的对象引用和接口变量,这必然会导致痛苦和痛苦。

我真的不能建议你的代码应该是什么样子的,因为我不知道你的问题是什么。我所做的一切都是为了向你解释这种行为。也许DoSomething应该返回IFoo而不是T。或者,您可能需要停止使用引用计数的生命周期管理。从这里很难确定。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12342313

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档