Option fields: great for scenarios where you want to provide a fixed, predefined list of values. Only a single value can apply and the user gets a convenient dropdown to select from. Perfect, until you want to extend the list of values.
Enter enums.
Documentation is here: https://docs.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-extensible-enums
The Theory
Enums are object types in their own right, not merely data types you can assign to fields or variables.
Let’s have a quick look at how it works. Who doesn’t love a calculator example?
Define a new enum like this:
enum 50100 Operator { Extensible = true; value(0; Addition) { Caption = 'Addition'; } value(1; Subtraction) { Caption = 'Subtraction'; } }
Notice the Extensible property. You need to explicitly decide that other apps can extend your values, which seems sensible. Use that enum as the data type for a table field or variable as you see fit.
Operator : Enum Operator;
As with options you’ll typically handle enums with a case statement. Also use the same double-colon syntax you use for options.
case Operator of Operator::Addition: exit(a + b); Operator::Subtraction: exit(a - b); else begin OnCalculate(a, b, Operator, Result, Handled); //event publisher if Handled then exit(Result); end; end;
Notice the else in the case block. There isn’t much point making the enum extensible if you don’t have a way to handle the extended values. We’re throwing an event for any Operator values that we don’t recognise. Perhaps we ought to also throw an error if the event is not handled as that would indicate someone has added an enum value without handling the calculation – but you get the idea.
Now another app developer can extend your calculator with some new operators in a dependent app.
enumextension 50100 OperatorExt extends Operator { value(50100; Sin) { Caption = 'Sin'; } value(50101; Cos) { Caption = 'Cos'; } value(50102; Tan) { Caption = 'Tan'; } }
The enumextension adds new values to the Operator enum. These values are not handled by the case statement above so the event is called. Subscribe to the OnCalculate event to provide the result and set the Handled flag.
The Practice
Three scenarios spring to mind where extending an enum could be particularly useful.
Adding On-premise Support
As a rule we try to write our extensions so that they can target either Business Central platform (SaaS or on-premise). The target property in app.json is set to “Extension” (or just omitted).
Let’s imagine that you want to use the .Net System.Math library to calculate the results of sin, cos and tan. You can’t use .Net in an app with a target of Extension.
What you could do instead is build your base calculator functionality in a SaaS-friendly, target-Extension app and add your .Net functionality in a dependent on-prem, target-Internal app instead.
I know, in the real world there are probably a bajillion free web services that could provide the result or you could use .Net in an Azure Function. Heck, you could even calculate the result manually if you really wanted (but seriously, don’t). Then again, in the real world you’re probably not making a calculator app.
You might want to handle things different if you’re running on-prem or on-SaaS though. For example, you might need to use .Net or interact with local resources like printers or file shares. Those are off-limits to SaaS apps. Rather than making your whole app target-Internal you could have a base app that you extend with your on-prem functionality.
Adding Additional Providers
Another model might be where you need several codeunits to provide some common functionality. Let’s say you have some integration with shipping agents – submitting consignment details, retrieving tracking numbers and label details etc.
You could create an enum with the name of the shipping agents that you integrate with in your app, but make allowance for that enum to be extended by other apps and throw appropriate events for them to handle integration with different agents.
Reusability
Finally, and perhaps most obviously is reusability. How many times have you copied option fields with the same option string and captions from one table to another? For instance, how many different places in standard does a “Document Type” field with an identical set of options occur? (I started to go through but quickly realised it was more than I could be bothered to count).
Instead of doing that you can just define the enum and its values once and reuse it – even if you don’t plan on making it extensible. You know it makes more sense.