I know that Delphi doesn't allow these kinds of type declaration, but this is what I need:
I have a dozen of enumeration types in my code and for each one of them I have a constant array of string that maps their elements to a caption. It's like this:
type
TMyEnum = (me0, me1, me2, me3, me4, me5, me6, me7, me8);
const
MyEnumCaptions: array[TMyEnum] of string = ('0', '1', '2', '3', '4', '5', '6', '7', '8');
Now my goal is to implement a function that takes a set of these enumerations and returns a list of captions as a string. To prevent defining a new function per each enumeration I used generics like what David did to answer an older question of mine. This is the code:
uses
System.SysUtils, System.TypInfo;
type
TMyEnumSet = set of TMyEnum;
TSet<T> = class
strict private
class function GetCaptionsList(PSet: PByteArray; const SizeOfSet(*in bytes*): Integer;
const Captions: array of string): string;
class function GetTypeInfo: PTypeInfo; inline; static;
public
class function IsSet: Boolean; static;
class function CaptionList(const Value: T; const Captions: array of string): string; static;
end;
...
{ TSet<T> }
class function TSet<T>.CaptionList(const Value: T; const Captions: array of string): string;
begin
if not IsSet then
raise Exception.Create('Invalid type in TSet<T>, T must be a set');
Result := GetCaptionsList(PByteArray(@Value), SizeOf(Value), Captions);
end;
class function TSet<T>.GetCaptionsList(PSet: PByteArray; const SizeOfSet(*in bytes*): Integer;
const Captions: array of string): string;
const
Masks: array[0..7] of Byte = (1, 2, 4, 8, 16, 32, 64, 128);
var
I, J: Integer;
begin
Result := '';
for I := 0 to SizeOfSet - 1 do
for J := 0 to 7 do
if (PSet^[I] and Masks[J]) > 0 then
Result := Result + Captions[I*8+J];
end;
class function TSet<T>.IsSet: Boolean;
begin
Result := GetTypeInfo.Kind=tkSet;
end;
class function TSet<T>.GetTypeInfo: PTypeInfo;
begin
Result := System.TypeInfo(T);
end;
And the usage:
TSet<TMyEnumSet>.CaptionList([me1, me3, me8], MyEnumCaptions)
My problem is that I have no control on the value passed as Captions
parameter. The most thing that I can do about it is to check its length like:
with GetTypeInfo^.TypeData^.CompType^.TypeData^ do
if (Low(Captions) <> MinValue) or (High(Captions) <> MaxValue) then
raise ...
And this is not enough since two enumerations may have same number of elements and I'll have to declare more of these enum-arrays in future. So I want something more solid like this:
TEnum<T> = class
public
type
S = set of T;
A = array[T] of string;
class function CaptionList(const ASet: S; const Captions: A): string; static;
end;
That is not allowed! But how can I achieve my goal without my problem?