Generics, Enumerated types and ordinal values

I wish this was a solution post, but it is a frustration post. I trying to figure out how I can use Ord() to convert an enumerated type to integer or cast an integer to an enumerated type using generics type arguments?


TSomeEnumType = (TheFirst, TheSecond, TheThird, TheFourth);

TEnumGen = class
class function Name(const Enum:TEnumType):String;
class function Value(const Ordinal:Integer):TEnumType;

class function TEnumGen.Name(const Enum: TEnumType): String;
Result := Format('%s.%s',
GetEnumName(TypeInfo(TEnumType), Ord(Enum)) // <-- Bombs

class function TEnumGen.Value(const Ordinal:Integer):TEnumType;
Result := TEnumType(Ordinal); // <- Bombs

Unfortunately there is no “enum” delimiter that can be used to tell the compiler that Ord() and casting of integers should be allowed for generic enumerated type arguments.

10 thoughts on “Generics, Enumerated types and ordinal values

  1. This should work (assuming Blogger doesn't eat it for dinner):class function TEnumGen.Name(const Enum: TEnumType): String;var Info: PTypeInfo; OrdValue: Integer;begin Info := TypeInfo(TEnumType); case GetTypeData(Info).OrdType of otSByte: OrdValue := PShortInt(@Enum)^; otUByte: OrdValue := PByte(@Enum)^; otSWord: OrdValue := PWord(@Enum)^; otUWord: OrdValue := PSmallInt(@Enum)^; otSLong: OrdValue := PLongWord(@Enum)^; otULong: OrdValue := PLongInt(@Enum)^; else raise EProgrammerNotFound.Create('New TOrdType element!'); end; Result := Format('%s.%s', [GetTypeName(Info), GetEnumName(Info, OrdValue)]);end;class function TEnumGen.Value(const Ordinal:Integer):TEnumType;begin Move(Ordinal, Result, SizeOf(TEnumType));end;

  2. Blogger was indeed hungry I see, if hardly famished… Obviously, it would be better if there were an ordinal type constraint (along with operator constraints and so on), but my suggested solution is quite general.

  3. TValue is your friend! :)class function TEnumGen.Name(const Enum: TEnumType): String;var  i: Int64;begin  TValue.From(Enum).TryAsOrdinal(i);  Result := Format('%s.%s', [GetTypeName(TypeInfo(TEnumType)), GetEnumName(TypeInfo(TEnumType), i)]);end;class function TEnumGen.Value(const Ordinal:Integer): TEnumType;var  v: TValue;begin  TValue.Make(Ordinal, TypeInfo(TEnumType), v);  Result := v.AsType;end;

  4. Stefan – nice! In fact, that allows doing away with an explicit call to GetEnumName entirely -class function TEnumGen.Name(const Enum: TEnumType): String;var  Value: TValue;begin  TValue.From(Enum);  Result := Format('%s.%s', [GetTypeName(Value.TypeInfo), Value.ToString]);end;

  5. Hi,Had a similar need when started with generics back with RAD 2009 and solved the cast this way:class function Generic.EnumToInt(const EnumValue: T): Integer;begin Result := 0; Move( EnumValue, Result, sizeOf(EnumValue) );end;class function Generic.IntToEnum(const IntValue: Integer): T;begin Move( IntValue, Result, SizeOf(Result) );end;which can be used as follows:class function Generic.StringToEnum(StringValue: string): T;begin Result := Generic.IntToEnum(getEnumValue( TypeInfo(T), StringValue ));end;class function Generic.EnumToString(EnumValue: T): string;begin Result := getEnumName( TypeInfo(T), Generic.EnumToInt(EnumValue) );end;but I agree TValue seems a more clean solution.

  6. Take a look at = (jjHigh,jjLow,jjHello_There);varJ: TEnum;S: String;Strs: TStrings;I: Integer;begin// Implicit assign of the friendly stringJ := 'Hello There';// implicit assign of enumorated name asJ := 'jjHello_There'; string// implicit ordinal assignJ := 2;// implicit assign of enumoratedtypeJ := jjHello_There;// This uses casting to select the proper implicit conversionWriteLn(String(J),'(',Integer(I),')');// Output should be 'Hello There(2)'// Add the enumorated type value to TStringsStrs.Add(J);end.