Study guide

8.3 Interfaces, Polymorphism & Dynamic Codeunit Invocation

Microsoft Dynamics 365 Business Central Developer MB-820

Track your progress as you read

Finished sections get a check mark.

1 Chapter 1: Business Central Architecture & Platform Foundation

1.1 Business Central Architecture & Extensions Model 1.2 Customization Lifecycle: Cloud (SaaS) vs. On-Premises 1.3 Base Application, System Application & AppSource

2 Chapter 2: Development Environment & Configuration

2.1: Development Environment Setup: VS Code, AL: Go! Projects & Sandboxes 2.2: AL Configuration Files: app.json & launch.json Parameters 2.3: Multi-Root Workspaces & Project Dependencies

3 Chapter 3: Extension Lifecycle: Debugging, Deployment, Multilanguage & Maintenance

3.1 Debugging & Snapshot Debugging in Visual Studio Code 3.2 Extension Deployment & Schema Synchronization Modes 3.3 Multilanguage Development with XLIFF & Translation Files 3.4 Extension Maintenance, Deprecation & Breaking Changes

4 Chapter 4: Tables, Table Extensions & Data Modeling

4.1: Building Tables, Fields, Keys & Data Types 4.2: Table Extensions & Table Modifications 4.3: FlowFields, FlowFilters & Table Relations 4.4: Enums, Enum Extensions & Extensible Types

5 Chapter 5: Pages, Page Extensions & Role Centers

5.1: Page Types, Anatomy & Control Structure 5.2: Building Card, List & Document Pages 5.3: Page Extensions & Page Customizations 5.4: Role Centers, Headlines & Cue Data Modeling

6 Chapter 6: Reports & Document Generation

6.1 Report Architecture, DataItems & Dataset Design 6.2 Report Layouts: RDLC, Word, Excel & Multilanguage 6.3 Document Reports & Request Page Programming 6.4 Processing-Only Reports & Report Substitutions

7 Chapter 7: XMLports & Data Exchange

7.1 XMLport Architecture, Formats & Properties 7.2 XMLport Node Hierarchy, Triggers & Stream Manipulation

8 Chapter 8: Codeunits, Events, Triggers & Interfaces

8.1 Codeunit Types, Execution & SingleInstance Codeunits 8.2 Events, Publishers, Subscribers & Event Isolation 8.3 Interfaces, Polymorphism & Dynamic Codeunit Invocation 8.4 Installation & Upgrade Codeunits, Data Transfer & Archive

9 Chapter 9: Entitlements, Permissions & Queries

9.1 Permission Sets & Permission Set Extensions 9.2 Inherent Permissions, Inherent Entitlements & Security Scoping 9.3 Query Objects: Joins, Aggregation & Query as Report Data Source

10 Chapter 10: UI Customization, User Assistance & Onboarding

10.1 Profile Objects & Custom Page Views in AL 10.2 User Assistance: ToolTips, Teaching Tips & In-App Tours 10.3 Assisted Setup, Guided Experience & Onboarding Checklists

11 Chapter 11: Business Central Design Patterns & Data Process Model

11.1 Functional Table Types: Master Data, Supplemental & Setup Patterns 11.2 Document Standards: Header, Line, History & Journal Architectures 11.3 Data Process Model & Posting Routine Architecture

12 Chapter 12: AL Language Fundamentals, Data Types & Variables

12.1 AL Syntax, Variable Scope, Primitive & Complex Data Types 12.2 Expressions, Control Flow Statements & Built-in Functions 12.3 Access Modifiers (Public, Internal, Local) & Code Scoping

13 Chapter 13: Data Manipulation, Streams & Error Handling

13.1 Record Operations: Get, FindSet, ModifyAll & Filter Functions 13.2 Streams, File Management & TempBlob 13.3 Error Handling: ErrorInfo, TryFunctions & Collectible Errors

14 Chapter 14: Testing, Test Toolkit & Automation

14.1 Testing Architecture & the Test Toolkit 14.2 Authoring Test Codeunits & UI Handler Functions

15 Chapter 15: Telemetry, Performance Optimization & Analyzers

15.1 Telemetry Configuration & Azure Application Insights 15.2 Custom Telemetry Signals with Session.LogMessage & KQL 15.3 Performance Profiler, SetLoadFields & Query Optimization 15.4 AL Analyzers: CodeCop, AppSourceCop, UICop & PTECop

16 Chapter 16: REST Web Services & JSON in AL

16.1 HttpClient, HttpRequestMessage & REST API Consumption 16.2 JSON Processing: JsonObject, JsonArray, JsonValue & JsonToken

17 Chapter 17: API Pages, OData, Read Scale-Out & OAuth

17.1 API Pages (PageType=API), OData Web Services & REST Endpoints 17.2 Bound and Unbound OData Actions with [ServiceEnabled] 17.3 Read Scale-Out Architecture & DataAccessIntent Configuration 17.4 Microsoft Entra ID App Registrations & OAuth 2.0 Integration

8.3 Interfaces, Polymorphism & Dynamic Codeunit Invocation

Key Takeaways Explain This Topic AI

Interfaces in AL define pure syntactic contracts of procedure signatures, enabling object-oriented polymorphism and adherence to the Open-Closed Principle in Business Central.

Codeunits implement interfaces using the 'implements' keyword, requiring exact compile-time signature conformity for parameter types, reference directions (var), and return types.

Extensible enums link interface definitions to concrete codeunits via the 'Implementation' property, enabling dynamic runtime instantiation without hardcoded CASE branching.

The DefaultImplementation and UnknownValueImplementation enum properties provide robust fallback mechanisms for uninitialized or unmapped ordinal values.

A single codeunit can implement multiple interfaces simultaneously, and interfaces facilitate isolated unit testing by enabling mock implementations without external network dependencies.

Last updated: August 2026

8.3 Interfaces, Polymorphism & Dynamic Codeunit Invocation

Prior to the introduction of interfaces in AL, writing extensible business logic with multiple interchangeable implementations required extensive CASE statements or complex hook events. If a third-party extension wanted to add a new calculation method, shipping carrier, or payment gateway, it had to subscribe to hook events and handle custom branching manually. AL interfaces enable object-oriented polymorphism by decoupling the definition of capabilities from their concrete execution, allowing dynamic runtime dispatch governed by extensible enums.

1. Interface Declaration & Syntax

An interface object in AL defines a contractual specification composed of procedure signatures. It contains no implementation code , no local or global variable declarations, and no triggers. It enforces a strict compile-time contract: any codeunit declaring that it implements the interface must provide concrete implementations for every procedure with identical parameter names, data types, parameter passing modes ( var vs. value), and return types. // 1. Interface Declaration

  • interface "IShippingCarrier"
  • {
  • procedure CalculateShippingCost(PackageWeight: Decimal; DestinationPostalCode: Code[20]): Decimal;
  • procedure GenerateTrackingNumber(ShipmentHeaderNo: Code[20]): Text[50];
  • procedure ValidateAddress(AddressLine: Text[100]; PostalCode: Code[20]; CountryCode: Code[10]): Boolean;
  • }
  • Rules for Interface Declarations

Procedure Signatures Only : Each declaration consists of the procedure name, input parameters, and optional return value. No begin...end blocks or variable blocks are permitted.

Access Modifiers : Procedures declared within an interface are implicitly public contracts.

Versioning Stability : Once an interface is published in an AppSource app or shared library, altering existing procedure signatures breaks all dependent codeunits. New capabilities should be introduced via distinct interface extensions or new interface objects.

2. Implementing Interfaces in Codeunits

Codeunits implement interfaces by specifying the implements keyword followed by the quoted interface name. Multiple distinct codeunits can implement the same interface, each encapsulating provider-specific business logic. // 2. Concrete Implementation: FedEx Carrier

  • codeunit 50120 "FedEx Shipping Provider" implements "IShippingCarrier"
  • {
  • procedure CalculateShippingCost(PackageWeight: Decimal; DestinationPostalCode: Code[20]): Decimal
  • begin
  • // FedEx rate calculation algorithm / API call
  • exit(15.0 + (PackageWeight * 1.75));
  • end;
  • procedure GenerateTrackingNumber(ShipmentHeaderNo: Code[20]): Text[50]
  • begin
  • exit('FDX-' + Format(CurrentDateTime, 0, '<Year4><Month,2><Day,2><Hours24><Minutes,2><Seconds,2>'));
  • end;
  • procedure ValidateAddress(AddressLine: Text[100]; PostalCode: Code[20]; CountryCode: Code[10]): Boolean
  • begin
  • // FedEx address validation service
  • exit((PostalCode <> '') and (CountryCode <> ''));
  • end;
  • }
  • // 3. Concrete Implementation: UPS Carrier
  • codeunit 50121 "UPS Shipping Provider" implements "IShippingCarrier"
  • {
  • procedure CalculateShippingCost(PackageWeight: Decimal; DestinationPostalCode: Code[20]): Decimal
  • begin
  • // UPS zone-based calculation algorithm
  • exit(12.5 + (PackageWeight * 2.10));
  • end;
  • procedure GenerateTrackingNumber(ShipmentHeaderNo: Code[20]): Text[50]
  • begin
  • exit('1Z999999' + ShipmentHeaderNo);
  • end;
  • procedure ValidateAddress(AddressLine: Text[100]; PostalCode: Code[20]; CountryCode: Code[10]): Boolean
  • begin
  • // UPS address validation logic
  • exit(StrLen(PostalCode) >= 5);
  • end;
  • }
  • Multi-Interface Implementation on a Single Codeunit

AL supports implementing multiple interfaces on a single codeunit. This allows a unified service codeunit to satisfy several distinct operational contracts across the system. interface "ILabelPrinter"

  • {
  • procedure PrintShippingLabel(TrackingNo: Text[50]; LabelFormat: Code[10]): Boolean;
  • }
  • // Codeunit implementing both IShippingCarrier and ILabelPrinter
  • codeunit 50122 "DHL Express Provider" implements "IShippingCarrier", "ILabelPrinter"
  • {
  • // IShippingCarrier implementation
  • procedure CalculateShippingCost(PackageWeight: Decimal; DestinationPostalCode: Code[20]): Decimal
  • begin
  • exit(18.0 + (PackageWeight * 1.50));
  • end;
  • procedure GenerateTrackingNumber(ShipmentHeaderNo: Code[20]): Text[50]
  • begin
  • exit('DHL-' + ShipmentHeaderNo);
  • end;
  • procedure ValidateAddress(AddressLine: Text[100]; PostalCode: Code[20]; CountryCode: Code[10]): Boolean
  • begin
  • exit(PostalCode <> '');
  • end;
  • // ILabelPrinter implementation
  • procedure PrintShippingLabel(TrackingNo: Text[50]; LabelFormat: Code[10]): Boolean
  • begin
  • // Direct thermal / PDF label generation logic
  • exit(true);
  • end;
  • }

Loading diagram... Enum-Driven Polymorphism & Dynamic Interface Dispatch Architecture

3. Dynamic Runtime Instantiation via Extensible Enums

The full architectural power of AL interfaces is realized when coupled with extensible enums . By mapping enum values directly to implementing codeunits, the AL runtime performs dynamic polymorphic instantiation without requiring brittle branching logic. enum 50120 "Shipping Carrier Type" implements "IShippingCarrier"

  • {
  • Extensible = true;
  • DefaultImplementation = "IShippingCarrier" = "Manual Carrier Provider";
  • UnknownValueImplementation = "IShippingCarrier" = "Manual Carrier Provider";
  • value(0; Manual)
  • {
  • Caption = 'Manual / Local Delivery';
  • Implementation = "IShippingCarrier" = "Manual Carrier Provider";
  • }
  • value(1; FedEx)
  • {
  • Caption = 'FedEx Express';
  • Implementation = "IShippingCarrier" = "FedEx Shipping Provider";
  • }
  • value(2; UPS)
  • {
  • Caption = 'UPS Ground';
  • Implementation = "IShippingCarrier" = "UPS Shipping Provider";
  • }
  • value(3; DHL)
  • {
  • Caption = 'DHL International';
  • Implementation = "IShippingCarrier" = "DHL Express Provider";
  • }
  • }
  • Eliminating Fragile CASE Statements

In traditional AL programming, selecting an algorithm based on an enum or option field required a CASE statement. If a third-party extension added a new option, the base CASE statement failed or ignored the new value. With interfaces, developers cast the enum variable directly to the interface variable: codeunit 50130 "Shipment Execution Engine"

{

procedure ProcessShipmentFreight(CarrierType: Enum "Shipping Carrier Type"; Weight: Decimal; PostalCode: Code[20]): Decimal

  • var
  • Carrier: Interface "IShippingCarrier";
  • FreightAmount: Decimal;
  • begin

// Dynamic runtime instantiation: The runtime creates the matching codeunit automatically!

Carrier := CarrierType;

  • FreightAmount := Carrier.CalculateShippingCost(Weight, PostalCode);
  • exit(FreightAmount);
  • end;
  • }
  • Adding New Providers in Independent Extensions

A separate ISV extension can add support for a new carrier (e.g., Royal Mail) without modifying the base app:

Declare a codeunit codeunit 50200 "Royal Mail Provider" implements "IShippingCarrier" .

Extend the enum: enumextension 50200 "Royal Mail Ext" extends "Shipping Carrier Type" .

Add value value(50200; RoyalMail) { Implementation = "IShippingCarrier" = "Royal Mail Provider"; } .

When the user selects RoyalMail on a shipping method, Carrier := CarrierType automatically resolves to Royal Mail Provider at runtime.

  • 4. Fallback Implementations & Test Mocking
  • DefaultImplementation & UnknownValueImplementation

To prevent unhandled runtime exceptions when data is incomplete or corrupted, AL enums support two critical fallback properties:

DefaultImplementation : Specifies the fallback codeunit to instantiate when an uninitialized enum variable (ordinal 0 or unassigned) is cast to an interface.

UnknownValueImplementation : Specifies the fallback codeunit when an unrecognized or unmapped ordinal value is encountered (for example, if a third-party extension that added an enum value is uninstalled, but existing records still contain that integer value in the database). enum 50125 "Tax Engine Type" implements "ITaxCalculator"

  • {
  • Extensible = true;
  • DefaultImplementation = "ITaxCalculator" = "Standard Tax Engine";
  • UnknownValueImplementation = "ITaxCalculator" = "Standard Tax Engine";
  • value(0; Standard)
  • {
  • Implementation = "ITaxCalculator" = "Standard Tax Engine";
  • }
  • value(1; Avalara)
  • {
  • Implementation = "ITaxCalculator" = "Avalara Tax Engine";
  • }
  • }
  • Testing with Mock Interface Implementations

Interfaces are invaluable for automated unit testing in Business Central. By implementing a mock codeunit that satisfies an interface contract, developers can test complex business logic without connecting to live external web services or incurring third-party API costs. codeunit 50140 "Mock Carrier Provider" implements "IShippingCarrier"

  • {
  • procedure CalculateShippingCost(PackageWeight: Decimal; DestinationPostalCode: Code[20]): Decimal
  • begin
  • // Return deterministic test data
  • if DestinationPostalCode = '99999' then
  • exit(0.0); // Free shipping test scenario
  • exit(25.0);
  • end;
  • procedure GenerateTrackingNumber(ShipmentHeaderNo: Code[20]): Text[50]
  • begin
  • exit('MOCK-TRACK-12345');
  • end;
  • procedure ValidateAddress(AddressLine: Text[100]; PostalCode: Code[20]; CountryCode: Code[10]): Boolean
  • begin
  • exit(true);
  • end;
  • }
  • Architectural Comparison: Interfaces vs. Events vs. CASE Statements

Feature AL Interfaces & Enums Event-Driven Hooks Legacy CASE Statements

Extensibility Model Open-Closed Principle (additive enum extensions). Decoupled subscribers listening to publishers. Closed monolithic branching.

Contract Enforcement Strict compile-time signature verification. Weak (parameter mismatches cause runtime issues). None (hardcoded branches).

Execution Pattern Exactly one concrete implementation per enum value. Multiple subscribers execute in non-deterministic order. Single branch matches ordinal.

Fallback Handling Native DefaultImplementation & UnknownValue . Manual handling via if not IsHandled then . else branch required.

Unit Testability High (swap enum with mock implementation). Moderate (manual binding required). Poor (requires mock database data).