Call TObject.GetInterface free object

I'm trying of execute a code like this:

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;

When I execute this code, f.free raise a exception, because is already free, I suppose, because if I comment this lines

Obj.GetInterface(IFoo, Foo);
Foo.DoFoo;

it work.

┬┐How can execute IFoo interface without free object?

thk.

ADD:

Thanks all. I understand.

I tried to return IFoo with same result. My problem is that T could not be TInterfacedObject. The Java code I trying to convert is:

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 example code:

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;

Answers


Let's take a look at this code:

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; 

After Obj := T.Create, the object has a reference count of zero, because no interface variable has yet referenced it. Then you call GetInterface and take an interface reference in Foo. So the object now has a reference count of 1. Then the function returns and Foo goes out of scope. This reduces the reference count to 0 and so the object is freed.

When you use TInterfacedObject, you must always hold an interface variable. So that the reference counting can manage the object's life. In this case you have mixed object references and interface variables and that invariably leads to pain and anguish.

I can't really advise you on what your code should look like because I don't know what your problem is. All I have attempted to do is to explain the behaviour for you. Perhaps DoSomething should be returning IFoo rather than T. Or perhaps you need to stop using reference counted lifetime management. Very hard to be sure from here.


Need Your Help

Why is this COM code leaking?

c++ windows com atl windows-shell

I'm maintaining an application which uses Windows Explorer overlay icons. Occasionally some operations require me to forcibly refresh explorers view for a particular folder. I do so using the fol...

JNLP: How to specifying installation directory and data to download?

java jnlp webdeploy

I wonder if one can let the user specify an installation directory for an application served by a JNLP file? For example:

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.