Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert Integer value to Enumeration Type [duplicate]

Tags:

delphi

Can I be sure that delphi assign integer number in a ascending sequence to any enumeration a my create ?

type
  TMyType = (mtFirst, mtSecond, mtThird); 

there for sure mtFirts is always TmyType(1) ???

I try to write code like myTypeselection := TMyType(MyRadiogroup.ItemIndex+1);

But I fail that the values Integer numbers are somehow mixed .

like image 900
Franz Avatar asked Jan 21 '26 09:01

Franz


2 Answers

The documentation has the answer:

By default, the ordinalities of enumerated values start from 0 and follow the sequence in which their identifiers are listed in the type declaration.

So your belief that numbering starts from one is in fact incorrect. It is the case the ord(mtFirst)=0, ord(mtSecond)=1 and so on.

Which means your code should read:

myTypeselection := TMyType(MyRadiogroup.ItemIndex);

Because radio group indexing is also zero based.

In my own code, I use the following generic class to perform operations like this:

type
  TEnumeration<T> = class
  strict private
    class function TypeInfo: PTypeInfo; inline; static;
    class function TypeData: PTypeData; inline; static;
  public
    class function IsEnumeration: Boolean; static;
    class function ToOrdinal(Enum: T): Integer; inline; static;
    class function FromOrdinal(Value: Integer): T; inline; static;
    class function MinValue: Integer; inline; static;
    class function MaxValue: Integer; inline; static;
    class function InRange(Value: Integer): Boolean; inline; static;
    class function EnsureRange(Value: Integer): Integer; inline; static;
  end;

class function TEnumeration<T>.TypeInfo: PTypeInfo;
begin
  Result := System.TypeInfo(T);
end;

class function TEnumeration<T>.TypeData: PTypeData;
begin
  Result := TypInfo.GetTypeData(TypeInfo);
end;

class function TEnumeration<T>.IsEnumeration: Boolean;
begin
  Result := TypeInfo.Kind=tkEnumeration;
end;

class function TEnumeration<T>.ToOrdinal(Enum: T): Integer;
begin
  Assert(IsEnumeration);
  Assert(SizeOf(Enum)<=SizeOf(Result));
  Result := 0;
  Move(Enum, Result, SizeOf(Enum));
  Assert(InRange(Result));
end;

class function TEnumeration<T>.FromOrdinal(Value: Integer): T;
begin
  Assert(IsEnumeration);
  Assert(InRange(Value));
  Assert(SizeOf(Result)<=SizeOf(Value));
  Move(Value, Result, SizeOf(Result));
end;

class function TEnumeration<T>.MinValue: Integer;
begin
  Assert(IsEnumeration);
  Result := TypeData.MinValue;
end;

class function TEnumeration<T>.MaxValue: Integer;
begin
  Assert(IsEnumeration);
  Result := TypeData.MaxValue;
end;

class function TEnumeration<T>.InRange(Value: Integer): Boolean;
var
  ptd: PTypeData;
begin
  Assert(IsEnumeration);
  ptd := TypeData;
  Result := Math.InRange(Value, ptd.MinValue, ptd.MaxValue);
end;

class function TEnumeration<T>.EnsureRange(Value: Integer): Integer;
var
  ptd: PTypeData;
begin
  Assert(IsEnumeration);
  ptd := TypeData;
  Result := Math.EnsureRange(Value, ptd.MinValue, ptd.MaxValue);
end;

With that at hand your code becomes:

myTypeselection := TEnumeration<TMyType>.FromOrdinal(MyRadiogroup.ItemIndex);
like image 167
David Heffernan Avatar answered Jan 24 '26 06:01

David Heffernan


If you don't specify values for your enumeration values, the compiler will start with zero, so this

TMyType = (mtFirst, mtSecond, mtThird)

is equivalent to

TMyType = (mtFirst = 0, mtSecond = 1, mtThird = 2)

If you use the correct start value 0, casting from integer to your enumeration and back is safe.

like image 27
jpfollenius Avatar answered Jan 24 '26 05:01

jpfollenius



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!