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;
Let’s take a look at this code:
After
Obj := T.Create, the object has a reference count of zero, because no interface variable has yet referenced it. Then you callGetInterfaceand take an interface reference inFoo. So the object now has a reference count of 1. Then the function returns andFoogoes 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
DoSomethingshould be returningIFoorather thanT. Or perhaps you need to stop using reference counted lifetime management. Very hard to be sure from here.