mirror of
https://github.com/microsoft/BCQuality.git
synced 2026-10-05 06:36:55 +01:00
Add foundational AL developer knowledge (#195)
Co-authored-by: Jesper Schulz-Wedde <jesper.schulzwedde@microsoft.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
38ad6b8810
commit
dd833133e0
23 changed files with 483 additions and 4 deletions
|
|
@ -0,0 +1,20 @@
|
|||
interface "I Quote Amount Bad"
|
||||
{
|
||||
procedure GetAmount(): Decimal;
|
||||
}
|
||||
|
||||
interface "I Quote Date Bad"
|
||||
{
|
||||
procedure GetDate(): Date;
|
||||
}
|
||||
|
||||
codeunit 50611 "Quote Reader Bad"
|
||||
{
|
||||
procedure GetDate(Quote: Interface "I Quote Amount Bad"): Date
|
||||
var
|
||||
DatedQuote: Interface "I Quote Date Bad";
|
||||
begin
|
||||
DatedQuote := Quote as "I Quote Date Bad";
|
||||
exit(DatedQuote.GetDate());
|
||||
end;
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
interface "I Quote Amount Good"
|
||||
{
|
||||
procedure GetAmount(): Decimal;
|
||||
}
|
||||
|
||||
interface "I Quote Date Good"
|
||||
{
|
||||
procedure GetDate(): Date;
|
||||
}
|
||||
|
||||
codeunit 50610 "Quote Reader Good"
|
||||
{
|
||||
procedure TryGetDate(Quote: Interface "I Quote Amount Good"; var QuoteDate: Date): Boolean
|
||||
var
|
||||
DatedQuote: Interface "I Quote Date Good";
|
||||
begin
|
||||
if not (Quote is "I Quote Date Good") then
|
||||
exit(false);
|
||||
|
||||
DatedQuote := Quote as "I Quote Date Good";
|
||||
QuoteDate := DatedQuote.GetDate();
|
||||
exit(true);
|
||||
end;
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
bc-version: [25..]
|
||||
domain: interfaces
|
||||
keywords: [interface, is-operator, as-operator, type-test, cast, variant, runtime-error]
|
||||
technologies: [al]
|
||||
countries: [w1]
|
||||
application-area: [all]
|
||||
---
|
||||
|
||||
# Guard optional interface casts with `is`
|
||||
|
||||
## Description
|
||||
|
||||
From runtime 15.0, AL can type-test an interface or `Variant` with `is` and cast it to another interface with `as`. The test is non-throwing, but `as` raises a runtime error when the underlying codeunit does not implement the target interface. This matters when an extended capability is optional or implementations can come from other extensions.
|
||||
|
||||
## Best Practice
|
||||
|
||||
Use `is` to establish that the value supports the target interface before using `as`. Cast directly only where the target implementation is an invariant guaranteed by the surrounding contract.
|
||||
|
||||
See sample: [`guard-interface-casts-with-is.good.al`](guard-interface-casts-with-is.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
Using `as` unconditionally for an optional extended interface. An otherwise valid implementation of the base interface then fails at runtime merely because it does not implement the additional contract.
|
||||
|
||||
See sample: [`guard-interface-casts-with-is.bad.al`](guard-interface-casts-with-is.bad.al).
|
||||
|
||||
## Reference
|
||||
|
||||
[Understand type testing and casting operators for interfaces](https://learn.microsoft.com/en-us/training/modules/business-central-interfaces/type-testing)
|
||||
Loading…
Add table
Add a link
Reference in a new issue