In the section "Sorting a TList<T>" you might have noticed a rather strange of use of a predefined interface, which had a generic declaration. It is worth looking into this technique in detail, as it opens up significant opportunities and changes (even if modestly) the way interfaces work in the language.
The first technical element to notice is that it is perfectly legal to define a generic interface86, like I've done in the GenericInterface example: type
IGetVa1ue<T> = interface function GetVa1ue: T; procedure SetVa1ue (Va1ue: T); end;
Notice that differently from a standard interface, in case of a generic interface you don't need to specify a GUID to be used as Interface ID (or IID). The compiler will generate an IID for you for each instance of the generic interface, even if implicitly declared. In fact, you don't have to create a specific instance of the generic interface to implement it, but can define a generic class that implements the generic interface: type
TGetVa1ue<T> = c1ass (TInterfacedObject, IGetVa1ue<T>) private fVa1ue: T; pub1 ic constructor Create (Va1ue: T); destructor Destroy; override; function GetVa1ue: T; procedure SetVa1ue (Va1ue: T); end;
While the constructor assigns the initial value of the object, the destructor's only purpose is to log that an object was destroyed. We can create an instance of this generic class (thus generating a specific instance of the interface type behind the scenes) by writing:
Sender: TObject); var aVa1: TGetVa1ue<string>; begi n aVa1 := TGetVa1ue<string>.Create (Caption); try
Log ('TGetVa1ue va1ue: ' + aVa1.GetVa1ue); fi na11y aVa1.Free; end; end;
86 This is the generic version of the IGetVa1ue interface of the IntfContraints example, covered in the earlier section "Interface Constraints" of this chapter. In that case the interface had an Integer value, now it has a generic one.
An alternative approach, as we saw in the past for the IntfConstraint example, is to use an interface variable of the corresponding type, making the specific interface type definition explicit (and not implicit as in the previous code snippet):
Sender: TObject); var aVal: IGetValue<string>; begi n aVal := TGetValue<string>.Create (Caption); Log ('IGetValue value: ' + aVal.GetValue); // freed automatically, as it is reference counted end;
Of course, we can also define a specific class that implements the generic interface, as in the following scenario (from the GenericInterface example): type
TButtonValue = class (TButton, IGetValue<Integer>) publ ic function GetValue: Integer; procedure SetValue (Value: Integer); class function MakeTButtonValue (Owner: TComponent; Parent: TWinControl): TButtonValue;
Was this article helpful?
What you need to know about… Project Management Made Easy! Project management consists of more than just a large building project and can encompass small projects as well. No matter what the size of your project, you need to have some sort of project management. How you manage your project has everything to do with its outcome.