During my AL training classes, a frequently asked question is how to convert enum values to and from integer or text. So I thought it would be a good idea to share with you what possibilities you have.
First of all, we need to understand the properties of an enum. Let’s look at an enum definition and see how it is constructed.

With these properties, you can always get from ordinal to name or from name to ordinal. But don’t make the mistake that ordinal and index are the same. They are not! Of course, in case you define the ordinal values as 1,2,3,… then they are identical to the index. But what if an enum is extended? Then ordinal value and the index will definitely not be identical anymore.
Example 1: Format
It’s quite common to use the Format command to convert a non-text value to text. You can do the same with the enum variable. Consider this code:
procedure EnumConvertDemo() var Level: Enum Level; begin Level := Level::Gold; Message(Format(Level)); end;
This results in a message with the caption of the enum value:




There are several standard formats properties that you can use. But none of them will convert the enum value to the name. The only value you can get with format is the caption or the ordinal value.
Format | Example |
Format(Level, 0, 0) | Gold level |
Format(Level, 0, 1) | Gold level |
Format(Level, 0, 2) | 30 |
Format(Level, 0, 9) | 30 |
Example 2: Getting the ordinal value
There is a different way to get the ordinal value. Instead of using the Format function you can use the method AsInteger(). With the code below, you get 30 in the integer variable.
procedure EnumConvertDemo() var Level: Enum Level; OrdinalValue: Integer; begin Level := Level::Gold; OrdinalValue := Level.AsInteger(); end;
Example 3: Getting the name value
The real name of an enum can be very useful in case of import or exports. Captions are not the best option. Maybe for export, it can be useful, but for imports, you better use the ordinal or the name. However, there is no method AsText() to directly get the name like you can with AsInteger() for the ordinal. But, there is a way to get it. Even with one line of code.
The enum variable has two properties: Names and Ordinals. Both properties return a list of text. See also the first picture in this post. The trick is to keep in mind that both lists do have equal length and the values at a certain index belong to each other. Let’s have a look at the code:
procedure EnumConvertDemo() var Level: Enum Level; OrdinalValue: Integer; Index: Integer; LevelName: Text; begin Level := Level::Gold; OrdinalValue := Level.AsInteger(); // Ordinal value = 30 Index := Level.Ordinals.IndexOf(OrdinalValue); // Index = 3 LevelName := Level.Names.Get(Index); // Name = Gold end;
This is a safe and generic way to get the name and it will also work with enumextension values.
What about one line of code, the above was three lines? Here you go:
procedure EnumConvertDemo() var Level: Enum Level; OrdinalValue: Integer; Index: Integer; LevelName: Text; begin Level := Level::Gold; LevelName := Level.Names.Get(Level.Ordinals.IndexOf(Level.AsInteger)); // Name = Gold end;
Example 4: Convert from integer
This is an easy one. If you have the integer value (not the index!) then you can convert to the enum with the method FromInteger().
procedure EnumConvertDemo() var Level: Enum Level; OrdinalValue: Integer; begin OrdinalValue := 30; Level := Enum::Level.FromInteger(OrdinalValue); end;
As you can see, I use Enum::Level here, because the Level variable itself does not have the FromInteger method. But, for sake of completeness, if I would give the enum variable a different name, then the Enum::Level is not even needed:
procedure EnumConvertDemo() var CustLevel: Enum Level; OrdinalValue: Integer; begin OrdinalValue := 30; CustLevel := Level.FromInteger(OrdinalValue); end;
This code example also indicates that variable naming is important and can influence the scope. I prefer using Enum::Level because that is similar to what we are used to with Database::Customer, Page::”Customer Card”, etc. and it is independent from variable names.
Example 5: Convert from text
With text I mean the name, not the caption. Again, there is no method FromName() like the FromInteger() method. So that is at least consequent. And consequently, we can get the enum value by making use of the Ordinals and Names property.
procedure EnumConvertDemo() var Level: Enum Level; OrdinalValue: Integer; Index: Integer; LevelName: Text; begin LevelName := 'Gold'; Index := Level.Names.IndexOf(LevelName); // Index = 3 OrdinalValue := Level.Ordinals.Get(Index); // Ordinal value = 30 Level := Enum::Level.FromInteger(OrdinalValue); end;
And again, this can also be written as one line of code:
procedure EnumConvertDemo() var Level: Enum Level; LevelName: Text; begin LevelName := 'Gold'; Level := Enum::Level.FromInteger(Level.Ordinals.Get(Level.Names.IndexOf(LevelName))); end;
Finally…
The Ordinals and Names properties are also available at Enum::Level. That means you don’t even have to use the variable for the conversion. If you want to get the ordinal from a name or vice versa, then this also works:
procedure EnumConvertDemo() var LevelName: Text; OrdinalValue: Integer; begin LevelName := 'Gold'; OrdinalValue := Enum::Level.Ordinals.Get(Enum::Level.Names.IndexOf(LevelName)); LevelName := Enum::Level.Names.Get(Enum::Level.Ordinals.IndexOf(OrdinalValue)); end;
In APIs it is quite normal to use the name value for enum fields. But you don’t need to write code in APIs to convert to the real enum value, that’s done automatically by the platform.
That’s it! Hope you enjoyed it!
One big problem is that these methods aren’t available for BC 14
Are you sure? I’m using a BC14 with plenty of usages of these methods
Really? Didn’t check that. In C/AL or AL? I’m lucky to be able to work with the latest version. 😊
A very nice elaborate post. Note that Dmitry Katson also discusses this too in his Areopa webinar https://www.youtube.com/watch?v=jTV70Rdk5Pc&t=42s
kindly make post on report errors fixing after convert from CAL to CAL
You mean how to fix errors in report after convert from C/AL to AL?
I’m afraid that is not really my expertise.
Hi AJK: we have converted some CAL code with 2 option fields, let says Option X and Option Y. They have almost the same option values: Option X has a,b,c,d. Option Y has b,c,d. Now the option have been converted to Enum objects.
In code we still use something like Option X := Option Y + 1 and SETRANGE(Option X, Option Y + 1). These lines give warnings and I want to get rid of them. What do you suggest? What is the savest way?
Can’t trust the index as these may vary when you install extension in a different order right? Should I use the Ordinal value or the Name?
As I understand it, the name Option Y determines the value for Option X. In other words, if Option Y = b, then you want to set Option X to b or filter it on b. No matter where ‘b’ is in the list of values of option X. Is that correct?
The safest way to do this is in two steps:
Step 1: Get the name of Option Y
LevelNameY := OptionY.Names.Get(OptionY.Ordinals.IndexOf(OptionY.AsInteger));
Step 2: Convert LevelNameY to OptionX
OptionX := Enum::OptionX.FromInteger(OptionX.Ordinals.Get(OptionX.Names.IndexOf(LevelNameY)));
I have found a workaround for BC14, see my post:
https://www.linkedin.com/feed/update/urn:li:activity:6721144582672789504
Hi Yuri,
would be nice if you could share your workaround somewhere I can see it. I even joined linkedin to see your post but I am still not able to see it. And “Yuri M” is not easy to identify. 🙂
I am using must current version of BC14 (CU17) and those functions are not available in AL.
Hi Markus,
see my comment in this post: https://stackoverflow.com/questions/63757853/how-do-i-iterate-the-enum-captions-in-business-central-365
I guess you cannot see it on LinkedIn because I have posted it in a group that you have not joined.
Hi,
I tried the follow code:
procedure main();
var
Level: Enum Level;
begin
Level := EnumConvertDemo(‘Gold’);
case Level of
Level::Gold: Message(‘Hello’);
end;
end;
procedure EnumConvertDemo(LevelName: Text): Enum Level;
begin
exit(Enum::Level.FromInteger(Level.Ordinals.Get(Level.Names.IndexOf(LevelName))));
end;
but return this error:
ArgumentOutOfRange – An invalid argument was passed to a ‘List’ data type method.
Could you help me?
Thank you.
Roberto.
it si because you have the enum caption and not the enum name
Do not forget that options are starting with 0 and IndexOf gives Position starting with 1.
Pingback: Deleting enum values – The BC Docs Librarian