Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass a mixture of differend enums types in delphi

I need to write a procedure where can pass different enum selections.

type
  TEnumOne = (eOneFlagOne, eOneFlagTwo);
  TEnumTwo = (eTwoFlagOne, eTwoFlagTwo);

The method should take different enums:

Process([eOneFlagOne, eTwoFlagTwo]);

I'm trying to implement it like this:

// does not work!
procedure Process(const Enums: array of Variant);
var aValue; Variant
begin
  for aValue in Enums do
  begin
    // of course, can't work...
    if aValue is TEnumOne then
  end; 
end;

So, is there a type instead of Variant, I can choose? Or is the a different approach, I dont' see?

like image 418
Francois Zbinden Avatar asked Jun 19 '12 23:06

Francois Zbinden


3 Answers

Meet the beauty of pascal.

Here's a working example of what you're probably trying to do:

program Project34; {$APPTYPE CONSOLE}

type
  TEnum=(eOneFlagOne,eOneFlagTwo,eTwoFlagOne,eTwoFlagTwo);
  TEnumSet=set of TEnum;

const
  cEnumOne=[eOneFlagOne,eOneFlagTwo];
  cEnumTwo=[eTwoFlagOne,eTwoFlagTwo];

procedure Process(const Enums: TEnumSEt);
var e:TEnum;
begin
  for e in Enums do
    WriteLn(ord(e));
end;

begin
  Process([eOneFlagOne, eTwoFlagTwo]);
  Process(cEnumOne);
  Process(cEnumTwo);
end.

Note that you can also declare the constants like this. Maybe that's clearer:

const
  cEnumOne:TEnumSet=[eOneFlagOne,eOneFlagTwo];
  cEnumTwo:TEnumSet=[eTwoFlagOne,eTwoFlagTwo];
like image 172
Wouter van Nifterick Avatar answered Oct 04 '22 13:10

Wouter van Nifterick


To be blunt, when you start trying to bend your language like this, it usually means that your approach is probably wrong. (not always, but usually) I'd be interested to hear what problem you are trying to solve, as maybe there is a better design option.

With what little we know about your problem, I would suggest that either you create 2 functions with the different signatures.
Or
if the required logic branch is similar enough to each other, then you could create a Generic method (assuming Delphi 2009 or higher) using the enum type as your generic parm.

...
procedure Process<T>(const enumParam : T) // Add a generic constraint here as well
begin
...
end;

Seems likely to me however, that the 2 different methods would be the likely best option (or something else entirely)

like image 45
Tim Jarvis Avatar answered Oct 04 '22 13:10

Tim Jarvis


RRUZ deleted his answer, here is a reworked version with type safety. RTTI is used to identify the different enum constants.

function EnumToString(const TypeInfo : pTypeInfo; Ix : Integer) : string;
begin
  Result := GetEnumName(TypeInfo, ix); 
end;

procedure Process( const Args : array of string);
var
  LIndex,ix : integer;
  EnumOne : TEnumOne;
  EnumTwo : TEnumTwo;
begin
  for LIndex := 0 to High(Args) do begin
    ix := GetEnumValue( TypeInfo(TEnumOne), Args[LIndex]);
    if (ix <> -1) then
    begin
      EnumOne := TEnumOne( ix); 
      // do something with EnumOne
      ...
      continue;
    end;

    ix := GetEnumValue( TypeInfo(TEnumTwo), Args[LIndex]);
    if (ix <> -1) then
    begin
      EnumTwo := TEnumTwo( ix); 
      // do something with EnumTwo
      ...
      continue;
    end; 
    ... 
    etc

  end;        
end;

Process( [EnumToString(TypeInfo(TEnumOne),Ord(TEnumOne.eOneFlagOne)),
          EnumToString(TypeInfo(TEnumTwo),Ord(TEnumTwo.eTwoFlagTwo))]);
like image 23
LU RD Avatar answered Oct 04 '22 13:10

LU RD