✏️ Explanatory Question

Extensions are mandatory, but not everything is extensible. What are your options when a standard method is private/final, a class is sealed, or an element (like a report) cannot be extended? How do you handle these edge cases the upgrade-safe way?

👁 4 Views
📘 Detailed Answer
🟢 Easy
💡

Answer with Explanation

D365 F&O • X++ INTERVIEW

Extensibility Edge Cases in Dynamics 365 Finance & Operations

Question 58 — What to do when a method, class or element is not extensible.

Interview Question

Extensions are mandatory, but not everything is extensible. What are your options when a standard method is private/final, a class is sealed, or an element (like a report) cannot be extended? How do you handle these edge cases the upgrade-safe way?

Model Answer (Short)

Since over-layering is deprecated, you must always reach for an extension first — but some targets aren't hookable. The strategy depends on what's blocking you. If a method isn't wrappable, look for a nearby delegate or Pre/Post event, or wrap a caller higher up that is extensible. If a class/method is sealed/private/final and Microsoft hasn't opened it, the correct route is to raise an extensibility request to Microsoft (they add hooks/attributes) — not to fork or copy the code. For report objects (which aren't extensible) you duplicate the report but extend the controller/DP/temp classes. As a last resort you can duplicate a small, isolated piece of standard logic — but this is discouraged because it won't receive Microsoft updates. The golden rule: extension → event/delegate → wrap a caller → request extensibility → (rarely) duplicate.

The Decision Ladder

Try these in order

  • 1. Chain of Command — wrap the method if it's public/protected and not final.
  • 2. Delegate / Pre-Post event — if the method itself isn't wrappable, subscribe to an available delegate or event.
  • 3. Wrap a caller — extend a higher-level method that is hookable and calls the blocked one.
  • 4. Request extensibility from Microsoft — ask them to add a hookable seam (attribute/delegate).
  • 5. Duplicate (last resort) — copy a small isolated piece; accept it won't get updates.
GOLDEN ORDER
CoCEvent/DelegateWrap callerRequest extensibilityDuplicate (rare)

Why not over-layer or fork?

  • Over-layering is deprecated for customer/partner code.
  • Forking/duplicating means you miss Microsoft updates and hotfixes.
  • It increases upgrade and maintenance cost and risk.
  • Only duplicate a small, well-isolated piece when there's truly no seam.

Common Non-Extensible Situations

Blocker Recommended approach
Method is finalFind a delegate/event or wrap a non-final caller
Method/class is privateWrap a public caller, or request extensibility
Class is sealedRequest Microsoft to open it; use surrounding events
Report objectDuplicate the report; extend controller/DP/temp classes
No hook anywhereRaise an extensibility request; duplicate only as last resort

Prerequisites (Rule 5)

  • Visual Studio with the Dynamics 365 developer tools.
  • A custom model / package for your objects.
  • Access to cross-reference to find callers and available delegates/events.
  • A channel to submit Microsoft extensibility requests (via support/LCS).

Code Example — Wrap a hookable caller instead of the blocked method

// The low-level method is final/private and cannot be wrapped.
// Instead, wrap the PUBLIC caller that invokes it.
[ExtensionOf(classStr(AbcPostingEngine))]
final class AbcPostingEngineAbc_Extension
{
    public void postDocument(AbcDocument _doc)
    {
        // Pre-logic before the (non-hookable) internal posting runs
        this.abcValidateBeforePost(_doc);

        next postDocument(_doc);   // caller IS hookable

        // Post-logic after posting
        this.abcNotifyAfterPost(_doc);
    }
}

Subscribe to an available delegate when the method isn't wrappable

class AbcPostingSubscriber
{
    [SubscribesTo(classStr(AbcPostingEngine),
                  delegateStr(AbcPostingEngine, postingCompletedDelegate))]
    public static void onPostingCompleted(AbcDocumentId _docId)
    {
        // React to the event Microsoft exposed, instead of editing the method
        info(strFmt("Posting completed for %1", _docId));
    }
}

Report edge case — duplicate report, extend the classes

// Report OBJECT is duplicated (not extensible), but the controller
// is EXTENDED so standard behaviour is reused.
class AbcSalesReportController extends SrsReportRunController
{
    public static void main(Args _args)
    {
        AbcSalesReportController controller = new AbcSalesReportController();
        controller.parmReportName(ssrsReportStr(AbcSalesReport, Report)); // duplicated report
        controller.parmArgs(_args);
        controller.startOperation();
    }
}

Points the interviewer wants to hear

  • Always prefer CoC → event/delegate → wrap a caller before anything drastic.
  • If nothing is hookable, request extensibility from Microsoft.
  • Report objects aren't extensible — duplicate the report, extend the classes.
  • Duplicating standard logic is a last resort (no updates).
  • Never over-layer or fork — it's deprecated and unsupported.

Likely Follow-up Questions

  • What do you do when the method you need to change is final?
  • How do you customize a standard report if it isn't extensible?
  • What is a Microsoft extensibility request and when do you raise one?
  • Why is duplicating standard code discouraged?

Key Takeaway

When a target isn't extensible, climb the ladder: Chain of Command → event/delegate → wrap a hookable caller → request extensibility from Microsoft → (rarely) duplicate. For reports, duplicate the object but extend the classes. Never over-layer or fork — it breaks the upgrade-safe promise.