8

Having the following generics class

 TTuple<T1, T2> = class
  protected
    fItem1: T1;
    fItem2: T2;
  public
    constructor Create; overload;
    constructor Create(Item1: T1; Item2: T2); overload;
    destructor Destroy; override;

    property Item1: T1 read fItem1 write fItem1;
    property Item2: T2 read fItem2 write fItem2;
  end;

constructor TTuple<T1, T2>.Create;
begin
  inherited;
end;

constructor TTuple<T1, T2>.Create(Item1: T1; Item2: T2);
begin
  fItem1 := Item1;
  fItem2 := Item2;
end;

destructor TTuple<T1, T2>.Destroy;
begin
  inherited;
end;

and used in a manner like:

x := TTuple<TObjectList<TMyObjects>, Integer>.Create;

I need to free fitem1 manually. How can I free the fItem1 inside the destructor?

3
  • 2
    Just write T1: class instead of T1 and you got the trick. In that way you have a "less generic" generic because T1 can only be a class type; since the compiler is aware of this fact, you'll be able to call Free Commented Mar 3, 2018 at 11:09
  • 1
    You can learn a lot of tricks for using Generics in Delphi looking at the source of System.Generics.Collections. TObjectList<T> and TObjectDictionary<TKey,TValue> will show you how the RTL uses the techniques outlined in @AndreiGalatyn response. Commented Mar 3, 2018 at 11:17
  • 2
    What does this class give you? It seems to offer an extra later of complexity for no benefits that I can discern. Or is it just an illustration? Commented Mar 3, 2018 at 13:06

1 Answer 1

9

In the definition of TTuple there is no restrictions on type of T1,T2. That is why you can't call destructor, because it can be any type, double/integer etc. Direct answer to your question:

  PObject(@fItem1).DisposeOf;

But it will work properly only when T1 is class. Proper solution is to define TTuple with restrictions on type:

TTuple<T1: class; T2> = class

Then you can free it in normal way:

fItem1.Free

To make it in Delphi-like style you can create two generic classes:

TTuple<T1,T2> = class
...
end;

TObjectTuple<T1: class; T2> = class<TTuple<T1,T2>>
  ...
  property OwnsKey: boolean;
end;

destructor TObjectTuple<T1,T2>.destroy;
begin
  if OwnsKey then
    FItem1.DisposeOf;
end;

For example look how it is implemented in

TObjectList<T: class>
Sign up to request clarification or add additional context in comments.

1 Comment

Is this safe? if PTypeInfo(TypeInfo(T1)).Kind = tkClass then PObject(@FItem1).DisposeOf;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.