0

If you want to know what is formdatafieldstr d365 x++ in chain of command, well it’s s a preprocessor X++ macro X++ which usually can be used in order to reference a control of a form as bound to particular field in a datasource.

Your FormButtonControl X++ class is actually in the Dynamics.AX.Application namespace and it is a class at the kernel level class for the app model in Dynamics 365 FinOps application model. Extending your FormControl class it is essentially a kind of button control your form might have.

Dynamics AX to D365FO beyond rebranding. In this free August 2025 D365 X Plus Plus development guide learn the technical insights into X++ and how they live in XML files, its powerful D365 Aug 2025 data manipulation features, and the nature of extension via extension classes in contrast with traditional object-oriented extensions in Java and C#.

D365 X Plus Plus Development Learning Guide August 2025 Dynamics Edge
D365 X Plus Plus Development Learning Guide August 2025 Dynamics Edge

Let’s also examine why SonarQube does not support X++ by giving a nice, clean overview of what SonarQube might usually be used for. Together, let’s go ahead and even also confirm whether Visual Studio and/or maybe even Visual Studio Code may or may not be officially supported for X++ development.

Introduction to X++ in Dynamics 365 Finance & Operations (D365 FO)

X++ Aug 2025 is known as the primary programming language used for developing business logic in Microsoft Dynamics AX (now rebranded as Dynamics 365 Finance & Operations) with Aug 2025 referring to the month of August in the year 2025, indicating that Dynamics Edge can be prepared to stay on top of the latest technological shifts in Dynamics 365 FinOps as of July 2025, August 2025 and beyond. It is such a modern, high-level language that resembles C# or Java in syntax, but is specialized for the ERP domain. The truth of the matter is that D365 X++ development aug 2025 might usually be described as an object-oriented, application-aware, and data-aware language. This means it supports all the tenets of object-oriented programming. It also means your professional modern finops platform is so tightly integrated with the Dynamics application’s framework, and has built-in understanding of the database schema. For more information please check out the Microsoft MB-500 Aug 2025 training class to learn more about how the rebranding from AX to D365 FO was far, far more than just a name change – it really did also come with significant architectural and tooling changes to the X++ language and development experience. Below, we go more into the training concepts you should know on X++ fundamentals (syntax, data types, operators, control flow, OOP, exception handling, database access) while we also may discuss how X++ compares to other languages as a high-level language,. Then we may explain to you about its unique features and recent changes. We also might cover development tool support here (Visual Studio vs. VS Code, SonarQube) and the extension model in X++ versus traditional extension in languages like C# and Java.

X++ Programming Fundamentals

D365 X++ Syntax plus Structure: D365FO X++ syntax aug 2025 might feel familiar to C#/Java developers because it also uses semicolons to end statements and curly braces { } to denote code blocks (for example, in loops or method bodies). Comments can be written with // for single-line or /* ... */ for multiline, just like in C#. Take note here that X++ is case-insensitive (unlike Java/C# which are case-sensitive). So basically the language’s basic structure (variables, expressions, control statements) could be considered very similar to other C-style languages. Makes it quite approachable for those coming from those backgrounds. For example, the arithmetic and assignment operators (+, -, *, /, =, etc.) and even increment/decrement (++, --) work the same way in X++ as they do in C#. Operator precedence in X++ is mostly the same as C#’s, though there are a few subtle differences – in complex expressions it’s advised to use parentheses to avoid any unexpected evaluation order.

Variables and Data Types: D365 X++ Aug 2025 offers you such a range of modern built-in data types and options suited so well for your future oriented business applications. Primitive types include integers (int for 32-bit, int64 for 64-bit), real (floating-point numeric), str (string), date, utcDateTime (date with time and timezone), enum (enumerations), boolean, guid (globally unique identifier), and others. There are also composite types or complex structures: for example, arrays (fixed or dynamic length lists of a single type), containers (a special structure that can hold mixed types, similar to a variant array), and classes (user-defined types). A unique composite type in X++ is the container, which can store heterogeneous data and is often used in older AX code – though in modern X++, container usage is less frequent in favor of classes or collections. Developers can also define Extended Data Types (EDTs), which are essentially aliases of primitive types with additional metadata (like a specific string size, label, or formatting) for consistency across the application. This improves readability and reuse – for instance, an EDT CustAccountId might be based on str but carry a standard length and label used everywhere in the system.

Operators: X++ supports a full range of operators for arithmetic, assignment, comparison, and logic. Assignment is done with =, and compound assignments like += and -= work as expected (e.g. x += 5; adds 5 to x). Arithmetic operators are +, -, *, / (float division), div (integer division), and mod (modulo). Bitwise operators (&, |, ~, ^) are available and behave the same as in C/C++/C#. Relational (comparison) operators are the standard ==, !=, >, <, >=, <=. X++ also provides logical operators && (AND), || (OR), and ! (NOT) for boolean logic. One thing to note is that X++ can treat certain non-boolean types as booleans in conditional situations. Take one example, an integer value of 0 might be treated as false and nonzero as true, and null object is treated as false. This is more permissive than C#, which requires an explicit boolean expression in conditions. So that means: an X++ if (myInt) { ... } is legal (executing if myInt != 0), whereas C# would require if (myInt != 0). This behavior is a legacy of older X++ (and similar to C/C++ truthiness) and is something to be mindful of for developers moving between languages.

Control Statements: X++  provides the usual control flow constructs found in high-level languages. Conditional execution uses if ... else statements and a switch statement for multi-branch selection. The X++ switch is similar to C#’s, but with a few differences: case labels in X++ can be variables or even comma-separated lists of values, not just constant literals, and a missing break will cause fall-through without a compile error (more like C/C++ switch behavior). For looping, X++ supports for loops (with initializer, condition, iterator syntax just like C#), while loops, and do...while loops. It also has a for ... select loop (often written as while select) which is a special construct to iterate through table records (more on that in the data section). In addition, X++ has a break statement to exit loops and continue to skip to the next iteration, functioning the same as in other languages. Overall, anyone familiar with languages like Java or C# will find X++ control flow very intuitive.

Classes and Object-Oriented Features: X++ is a fully object-oriented language: you can define classes with methods and properties, instantiate objects, and use inheritance and polymorphism. A class is declared with the class keyword, and if no inheritance is specified, it implicitly extends the root Object class. X++ supports single inheritance (one base class) via the extends keyword, and also interface implementation with implements (much like Java/C# interfaces). Within classes, you can define member variables and methods. Access modifiers available are public, protected, and private for methods (and essentially for member variables as well, though typically those are kept private). X++ also has an internal concept implicitly via the package scoping, but primarily one uses the three main access levels. Polymorphism is supported – methods can be overridden in subclasses (unless marked final) and X++ will dynamically dispatch to the most-derived override when an object’s method is called. Something to really take note of: X++ did not historically require an explicit override keyword to override a base class method – you just define a method with the same name/signature in the subclass and it overrides the parent’s method. In current D365 FO X++, a method can be marked final to prevent overriding, and conversely abstract classes and methods are supported (an abstract method has no body and must be overridden). All of this is analogous to Java’s class model. X++ even supports reflection on classes at runtime, and interoperability with .NET classes (you can instantiate and call .NET classes from X++ and vice versa). This OOP capability makes X++ quite powerful for structuring large ERP application code into manageable classes and frameworks.

Exception Handling: Error and exception handling in X++ uses a familiar try-catch-finally paradigm. You enclose risky operations in a try { ... } block and catch exceptions with one or more catch blocks following it. Inside a catch, you can handle specific exception types (often represented by X++ exception enums or classes) or do a generic catch of Exception. X++ also supports a finally block after catch, which executes cleanup code regardless of whether an exception occurred. Throwing exceptions is done via the throw keyword, which can throw an instance of an exception class or a specific exception enum (X++ defines a set of exception codes in the Exception enum, such as Exception::Error). Additionally, X++ provides a global function throw error("message") or simply error("message") to raise an exception with a message. One special feature in X++ is the retry statement inside a catch block – if you catch an exception and resolve the issue, you can use retry to jump back and re-execute the try block. This can be useful, for example, if you catch a database deadlock exception, you might wait and then retry the operation. However, developers must use retry carefully to avoid infinite loops. Also, it’s important to note that if an exception occurs inside a database transaction scope (between ttsBegin and ttsCommit in X++), the transaction is automatically aborted/rolled back and the exception cannot be caught inside that transaction – it will bubble out of the transaction block. In other words, X++ will always roll back the transaction on error and you can only handle the exception after the rollback. This behavior encourages handling errors outside the immediate data operation to maintain data integrity.

Database Access and Data Manipulation: One of the hallmark features of X++ is its integrated SQL-like data manipulation capabilities. X++ is tightly coupled with the underlying Microsoft SQL Server database of D365 FO, to the point that you can write SQL operations directly in the language. The primary means of data access is the select statement in X++ – which looks like a simplified SQL SELECT. For example, you can write: select custTable where custTable.AccountNum == 'US-001'; to retrieve a customer record, or use joins and aggregate functions right in X++ syntax. Under the hood, the X++ runtime translates these select statements into real SQL queries to execute on the database. This tight coupling is why we say X++ is data-aware – the language “knows” about the database schema (tables, fields, indexes) and allows developers to use SQL keywords directly within X++ code. For instance, X++ supports keywords like firstOnly (to select only the first matching record), forUpdate (to lock records for update), exists join (translates to SQL EXISTS sub-query), and other SQL-like constructs as part of the language. The X++ compiler and environment are aware of table definitions, so writing CustTable cust; select cust where cust.AccountNum == "US-001"; is a strongly-typed operation – cust.AccountNum is checked against the schema, and the result is a CustTable record buffer object.

Beyond simple selects, X++ provides a rich set of data manipulation statements that cover inserts, updates, and deletes without requiring raw SQL. For example:

  • To insert data: you can either assign values to a table buffer and call insert() method (which inserts that one record), or use insert_recordset to insert multiple records in one go (set-based insert).
  • To update data: similarly, you can update a single record by modifying the buffer and calling update(), or use an update_recordset statement to update multiple records in a single operation (e.g. increment all prices by 5% in one query).
  • To delete data: you can delete single records via delete() (or doDelete() for deferred deletion in transactions), or use a delete_from statement to delete a set of records matching a condition.

All of these are built-in language features. The advantage is that X++ developers manipulate data at a high level of abstraction – dealing with table objects and field assignments – and the system handles generating efficient SQL behind the scenes. For example, an X++ while select * from CustTable join DirPartyTable will automatically be executed as a proper SQL join between the Customer and Party tables, returning results that X++ code can iterate. There are even aggregate functions like sum, avg, minof, maxof that can be used in select statements to get aggregated values from the database in one go. And if needed, X++ provides the RecordInsertList and RecordSortedList classes for batch operations and a SysDa API for data access that can mimic these operations via code (useful in some extension scenarios). Because these data access capabilities are part of the language, they automatically enforce security and business logic that is defined in the application. For instance, any record-level security or table validations in the ERP system will be honored by X++ select/insert/update statements, whereas an external code (say a C# app querying the database) would bypass those unless explicitly coded. This is a huge benefit of X++’s data-aware design: it provides powerful native data manipulation features (more precise than just calling it “robust”) that enable developers to work with database records in a natural and efficient way, while maintaining the integrity of business rules.

X++ as a High-Level Language (Comparison with Others)

X++ is considered a high-level programming language, meaning it provides a strong level of abstraction from machine details, manages memory for you (through automatic garbage collection), and offers rich language constructs to improve developer productivity. In practice, working with X++ is similar to working with other modern high-level languages like C# or Java: you focus on business logic, and the runtime (or underlying platform) handles lower-level details such as memory allocation and database query optimization. For example, X++ has automatic garbage collection to clean up objects that are no longer referenced, just as Java and C# do with their runtimes.

Compared to low-level languages (like C or C++ or assembly), X++ does not require manual memory management or direct manipulation of pointers. You cannot perform pointer arithmetic in X++ or manage memory addresses – those are handled by the .NET CLR once X++ is compiled to IL. This makes X++ safer and easier for application developers, at the cost of not being able to fine-tune performance at the hardware level (which is usually not a concern in business applications). In other words, X++ trades off some control for a lot of convenience, which is exactly what a high-level language is supposed to do.

In terms of syntax and capabilities, X++ aligns closely with languages like C# and Java (object-oriented, curly-brace syntax, etc.), so much so that a C# developer can read most X++ code and understand it with minimal orientation. Fundamental concepts such as classes, inheritance, polymorphism, loops, exception handling, etc., exist in all these languages and work in analogous ways in X++. However, X++ differentiates itself by being domain-specific to the Dynamics 365 FO environment. Unlike general-purpose languages, X++ has built-in keywords and frameworks for things like database transactions (ttsBegin/ttsCommit for demarcating transactions), and integrates with the application’s data model and security model. C# and Java by themselves have no concept of an “ERP database table” or “user session context” – you’d have to use external libraries or frameworks to work with databases or enterprise systems. X++, on the other hand, was designed with enterprise data and business logic in mind from the start. This means a developer using X++ can accomplish certain ERP tasks with far less code than a C# developer would need if trying to do the equivalent from outside the system. For example, retrieving a customer’s record and checking a field might be a one-liner in X++, whereas in pure C# you’d need to write a SQL query or call a service and handle connection objects, etc..

Another point of comparison: compilation and runtime. Historically, X++ was compiled to an intermediate p-code that was interpreted by an AX kernel, which made it somewhat slower and more isolated than languages like C#. Starting with D365 FO, X++ is now compiled to Microsoft .NET CIL (Common Intermediate Language), the same intermediate language used by C# and VB.NET. This means at runtime, X++ literally runs as managed .NET code on the CLR alongside C# code. As a result, X++ gained performance (closer to C# speeds) and can interoperate with other .NET languages much more easily. For example, you can reference .NET assemblies in X++ and even instantiate C# classes or call .NET framework functions from X++ code. Conversely, you can expose X++ logic as services that a C# program could call. This blurs the line between X++ and other high-level languages – in D365 FO they are all part of the same managed environment. In summary, X++ stands as a high-level, specialized language: it offers the ease-of-use and power of high-level languages (like memory management, rich libraries, etc.), while being tailored to work within the Dynamics 365 ecosystem (aware of application and data). High-level languages like C# and Java are more general-purpose (you can build desktop apps, web servers, anything), whereas X++ is generally used only within the Finance & Operations context. This specialization means X++ isn’t as widely applicable, but within its domain it can be more efficient for developers. As some experts note, knowing C# offers broader opportunities, while X++ is a niche skill – it’s all about using the right tool for the job.

Object-Oriented, Application-Aware, and Data-Aware Language

As noted, X++ is object-oriented: you define classes and objects to model business entities and processes. It supports inheritance, polymorphism, and even interfaces, allowing developers to use familiar OO patterns when writing code for things like invoices, ledgers, or workflows. For example, you might have a base class Document and subclass it into InvoiceDocument or PurchaseOrderDocument with overridden methods – X++ fully supports that kind of design. Being object-oriented is crucial for an enterprise language because it helps encapsulate complex business logic and makes code more maintainable.

Application-aware means that X++ has knowledge of the application context and provides keywords/features that tie into the application’s runtime environment. In Dynamics AX (the predecessor to D365 FO), there were keywords like client and server that you could use to dictate where code should run (client-tier vs server-tier). This was important in the old client-server architecture. In today’s cloud-based D365 FO, nearly all X++ code runs on the server tier, but this heritage explains some of the “app-aware” capability. Another example is the changecompany keyword, which allows X++ code to execute under a different company (legal entity) context for data access – effectively telling the application to switch the data partition for the code that follows. This is something specific to an ERP multi-company environment. X++ also has method modifiers like display and edit for form methods, which directly relate to the UI behavior in the application. A display method in X++ is used to calculate a value on the fly for showing in a form field (without storing it in the database), and an edit method allows custom logic when a user edits a field in the UI. These concepts don’t exist in general languages – they exist because X++ “knows” it’s running as part of an application with forms, records, and user sessions. In summary, X++’s application-aware nature is evidenced by keywords and frameworks that are useful for writing client/server ERP applications, as one source describes: it includes keywords like client, server, changecompany, display for ERP UI/logic, which you wouldn’t find in a vanilla programming language.

Data-aware refers to X++ being conscious of the database and data model. We’ve covered a lot of this already in the data manipulation section – X++ code can directly work with tables as if they were classes, using field names and relationships without writing raw SQL. The language includes many SQL-like keywords (such as firstOnly, exists join, forUpdate, sum, etc.) specifically for database operations. A concrete illustration: if you have a table CustTable with field AccountNum, you simply declare a variable of type CustTable and use it in a select, and you can access custTable.AccountNum directly in X++ code. The language and compiler know that CustTable and its fields exist (thanks to the AOT metadata). There’s no need to create separate data access classes or OR mappers – the table is treated like a class. This tight coupling of language and database is why X++ is called data-aware – it “knows” about the data model and can embed SQL within the language seamlessly. In contrast, a language like C# has no built-in notion of a database table; you must use an external library or ORM (like Entity Framework) or write SQL manually to talk to a database. X++ essentially has a built-in ORM and database connectivity by design. This leads to faster development for data-heavy business logic and ensures that any database operation obeys the business’s security and validation rules inherently.

To summarize, being object-oriented gives X++ the structure and reuse benefits we expect from modern languages, being application-aware means it directly supports the ERP application’s runtime concepts (UI, client/server, user session, etc.), and being data-aware means it has first-class support for database operations and understands the data schema. These combined characteristics make X++ particularly effective for enterprise software development where you constantly interact with data and the application framework. It’s quite unique to find a language that is both high-level general-purpose and so deeply integrated with an application’s domain. One Microsoft document described X++ as having keywords useful for writing “client/server ERP applications and programming database applications” – essentially underlining its app-aware and data-aware nature.

Evolution from Dynamics AX to D365 FO: What Changed?

X++ has its roots in Microsoft Dynamics AX (previously known as Axapta). With the transition to Dynamics 365 for Finance and Operations (D365 FO), X++ remained the core language, but the platform around it underwent major overhauls. Here are some significant changes and improvements since the AX 2012 era, beyond just rebranding:

  • Development Environment (IDE): The old MorphX IDE (integrated into the AX client) was replaced with Microsoft Visual Studio in D365 FO. IDE stands for Integrated Development Environment and it’s essentially your modern code editor and environment. Developers now use a customized X++ IDE Aug 2025 version of Visual Studio 2015+ with Dynamics 365 developer tools. This is a huge shift – you get all the perks of Visual Studio (better editor, IntelliSense, debugging, source control integration, etc.) instead of the proprietary MorphX editor. In AX 2012, code was organized in layers and models within a model store database; in D365 FO, the application’s elements are file-based (more on that shortly). Each developer typically works on a personal dev environment (often a VM), and collaboration uses source control like Azure DevOps (TFS) or Git, rather than the old model store layering for merging code. This modernization of the dev environment aligns X++ development with standard software engineering practices.
  • Compilation to .NET CIL: In AX 2012, X++ code was compiled to p-code (pseudo-code) which was interpreted at runtime by the AX interpreter, with an option to generate .NET CIL for certain processes. D365 FO completely rewrote the X++ compiler to generate .NET Intermediate Language (IL) only, eliminating p-code entirely. Now, every X++ compile produces a .NET assembly. The benefits are multiple: IL executes much faster than interpreted p-code, you no longer need the old .NET Business Connector to interface with external .NET code (since everything is running on the CLR natively), and interoperability with other .NET languages is seamless. Microsoft notes that code runs much faster in D365 FO than in AX 2012 due to this change. This also means the deployment artifact of your code is a standard .NET assembly (a DLL) packaged in the deployable package, rather than layered XPOs or model store data.
  • Model Store and XML-Based Artifacts: In AX 2012, all application elements (tables, classes, forms, etc.) and even the compiled p-code lived in a SQL database called the model store. In D365 FO, the entire model store is file-based – represented as XML files organized into folders per model/package. Each element (a table, a class, a form) is an .XML file containing its metadata and source code if applicable. For example, a class MyClass would be stored as an XML file that includes its properties and the X++ source code of its methods embedded within. This is why one might say “X++ code resides in XML files”. It’s true: if you navigate the AOT in Visual Studio and open a class, behind the scenes Visual Studio is editing an XML file where the code is inside a CDATA section (or a similar construct) representing the method source. This design facilitates better integration with version control (diffing, merging XML is easier than dealing with binary model store files) and enables deployment packages to be produced as bundles of these compiled assemblies and associated metadata. It’s important for developers to know this because it affects how customizations are transported and merged. For instance, upgrading the application involves merging XML changes, and if something goes wrong, one might inspect those XML files to resolve conflicts. It also means that to add a new element or code, you must go through the proper tools (Visual Studio, the AOT) – manually editing the XML isn’t supported and could break things if not done exactly right. In summary, the entire application’s definition is now in human-readable XML plus compiled DLLs, which is a big change from the opaque database modelstore of AX 2012. The XML-based approach is a cornerstone of the new service updates model: Microsoft can ship updates that just modify certain XML artifacts and we merge them rather than overwriting whole layers.
  • Extension Overlayering Model: Perhaps the most impactful change for developers is the shift from overlayering to extensions. Overlayering (in AX 2012) meant you could directly customize Microsoft’s code by overlaying your code on a higher layer – essentially overriding or modifying the original definitions. This was powerful but caused huge headaches during upgrades (merging your changes with new Microsoft code). In D365 FO, Microsoft has disallowed overlayering of its application code. Instead, you must use extensions to customize or extend functionality. An extension means you leave the original object intact and add your additional logic either by event handlers or by so-called “class extensions” (also known as class augmentation). For example, if you want to add a method to standard class SalesTable, you create a new class SalesTable_Extension and add your method there, rather than editing the original SalesTable class. Or if you want to change what happens when a form’s button is clicked, you might write an event handler that runs after the standard code, instead of altering the form’s code directly. Microsoft enforced this by sealing the base packages: in early versions of D365 FO you’d get warnings if you overlayered, and later versions throw errors if you attempt to modify base objects. The move to extensions ensures that when Microsoft updates the base code, your additions are isolated and less likely to break or conflict. We will discuss more on how extension classes work in the next section, but it’s worth noting here as a key change. In short, customization methodology changed: D365 FO favors composition over modification, which improves upgradability.
  • Cloud and Deployment Changes: AX was typically on-premises or private hosted, whereas D365 FO is primarily a cloud-hosted solution. This influences developers in that you no longer deploy changes by XPO import or model store hot-swaps on a running system. Instead, you develop on a dev machine, then build a deployable package (which is essentially the compiled code, metadata, and model info) and apply it to a sandbox or production via a controlled process. The deployable package is a compiled, sealed output – customers can’t see the source in it, unlike AX 2012 where delivering a model could include source code. This protects intellectual property of ISVs and enforces that production systems run compiled code only. Another change is that developers cannot directly connect to the production database or AOT; all interaction is through the application or LCS (Lifecycle Services) processes. This is more of a platform shift than an X++ language change, but it’s part of the context in which X++ now operates.

All these changes mean that while X++ the language still has the same syntax and general behavior, the way we develop and deploy X++ code in D365 FO is very different from AX 2012. The result is a more modern development cycle, closer alignment with .NET practices, and a system that is easier to keep up to date. Microsoft’s documentation and community resources emphasize moving existing AX customizations to the extension model for these reasons. In summary, besides the rebrand, X++ has evolved to be faster (via IL), safer to customize (via extensions), and more aligned with standard development tools (via Visual Studio and file-based code), which are substantial improvements over the AX era.

Development Tools: IDE Support and SonarQube Analysis

Developing in X++ today requires Microsoft Visual Studio with the Dynamics 365 FO Developer Tools installed. Visual Studio is the only supported IDE for genuine X++ development – specifically, for D365 FO the recommended version was Visual Studio 2015 or later with the Dynamics extensions. When you provision a D365 FO development VM from Microsoft, it comes with Visual Studio preconfigured for X++ work (including the “Dynamics 365” menu and tools). Visual Studio Code, on the other hand, is not an official or practical option for X++ development. There is no mature extension for VS Code that can compile or work with X++ AOT elements, and the development environment relies on a lot of integrated tooling that VS Code cannot replicate. As an expert on the Dynamics forums succinctly put it: “Visual Studio 2015 is the exclusive IDE for development” in Dynamics 365 Finance & Operations. While some community attempts have been made (one could find a rudimentary VS Code syntax highlighter, for example), you cannot actually build and deploy X++ code with VS Code. This is largely because the development VMs have many moving parts – a local AOS, SQL, and the VS integration that performs compilation and synchronization of the data dictionary. Those cannot be easily re-engineered for a lightweight editor. A Stack Overflow discussion confirmed that using VS Code for AX7/D365 development is not feasible without heavy re-engineering, and no official support exists. Therefore, developers should stick with Visual Studio for any serious X++ work.

Regarding SonarQube and static code analysis: SonarQube is a popular code quality and analysis tool, but unfortunately it does not support X++ at this time. The SonarSource team has stated that there are no current plans to add X++ language support, though they have noted the request for future consideration. This means you cannot run SonarQube to automatically check X++ code for issues or track technical debt in the same way you would for, say, C# or Java. The reason is simply that X++ is a niche language and SonarQube’s built-in analyzers don’t recognize its syntax. In fact, if you tried, SonarQube would treat X++ files as plain XML or text and wouldn’t know how to parse the code. A Microsoft MVP on the Dynamics community forums confirmed this, explaining that SonarQube or similar third-party tools “are not aware of the X++ code language” and thus “the tool can’t help here”. Instead, the recommendation is to use the built-in code analysis tools that come with the Microsoft development environment. Visual Studio (with the D365 FO add-ins) can perform Best Practice Checks and more advanced static analysis (Microsoft provides rule sets like SocrateX and AppChecker for X++ code quality) when you build your code. These tools will catch things like dead code, bad practices, SQL performance issues, and so on, as part of the compile/build process. Essentially, Microsoft’s own tooling fulfills some of the roles that SonarQube might for other languages.

You may want to go ahead and take a note that SonarQube could be extended by using custom plugins to support new languages, so that means theoretically an open-source effort could add X++ support. But as of now (2025), no widely-used plugin really exists for X++. Therefore, organizations are advised to rely on Microsoft’s supported tools for code review and quality checks. Also, since X++ development is done in Visual Studio, you can leverage some general VS extensions (like ReSharper to an extent, or Visual Studio’s code formatting) for X++ code as well – though not all C# tooling will understand X++ syntax.

So all this means, Visual Studio is the supported development interface for X++, and neither Visual Studio Code nor SonarQube are really part of the official or recommended toolchain for D365 FO development. Sticking with the Microsoft-provided IDE and using its built-in analyzers will ensure you remain within supported and documented practices, which is important given the enterprise nature of the applications.

X++ Code in XML Files: How and Why

As mentioned earlier, in D365 FO the application’s elements (including X++ classes, tables, forms, etc.) are stored as XML artifacts in the AOT (Application Object Tree) on disk. Each element is an XML file containing metadata and, if applicable, the source code. For example, a class definition file will list properties like the class’s name, any attributes, and have sections for each method where the X++ code is included as text. Typically, the code is enclosed in a CDATA section within the XML to preserve all characters. The system uses these XML files as the source – when you build the project in Visual Studio, it reads the XML and compiles the X++ code within into the .NET assembly.

Why this design? The shift to XML files was primarily to facilitate distributed development and modern ALM (Application Lifecycle Management). In AX 2012, code and metadata lived in a database, which made source control and team collaboration difficult (you had to export XPO files or use specialized layers). Now, because everything is file-based, you can use standard version control systems (Git, TFVC) to manage the X++ code just like any other codebase. Each developer can have a local copy of the XML files, merge changes, diff them, etc., which is a huge improvement. Moreover, the build output is clearly defined (the XML -> compiled DLL), and build servers can compile the code without needing an AX client instance – just the build tools.

From a technical perspective, the entire model store is a set of folders with XML files organized by model. Classes and forms are explicitly given as examples of elements represented by XML containing both metadata and source code. This means if you browse the application directory on a dev machine, you might see something like ...\ApplicationSuite\AxClass\MyClass.xml – opening that, you’d find an XML document with a structure describing MyClass and inside it, tags for each method with the X++ code inside. It’s important for developers to know this because sometimes you may need to inspect these files outside of Visual Studio (for instance, to troubleshoot a merge or understand how an element is defined). Also, when deploying, the package you create essentially bundles up these XML (and the compiled binaries) into a deployable unit. If there’s ever a need to manually compare environments or ensure a certain customization is present, you might compare these XML definitions.

However, in day-to-day work, you typically don’t edit the XML directly – you use Visual Studio’s designers and editors. Visual Studio hides the XML from you; when you add a new method in the editor, it’s actually updating the underlying XML. There have been rare scenarios where advanced users manipulate the XML (like find & replace across many files to rename something), but one must be cautious doing so. The XML format also reinforces the concept of metadata vs. code: a lot of what you do in Dynamics (adding fields to a table, creating a menu item, etc.) is actually metadata configuration which is also stored in these XML files, not code per se. The code (X++ methods) is just one part of the overall model.

X++ code being stored in XML is a behind-the-scenes implementation detail that reflects the modernized architecture of D365 FO. It’s important to know why it is that way: it allows for better source control integration and deployment packaging, and it aligns the development of X++ with file-based project systems like other .NET projects. It also means that what you see in the AOT is not a mystical repository – it’s literally reading those XML files into a tree view. Knowing this can help demystify the build and deployment process (for example, understanding why a build might fail if an XML is malformed, or how an element is represented). Ultimately, this approach contributes to making Dynamics 365 FinOps development more approachable to traditional software developers, since under the hood, it’s not too different from, say, an ASP.NET project composed of configuration XML and C# code files (though in X++, both are combined in the XML). The key takeaway is that the code and meta-data are decoupled from the runtime until compilation, enabling a more flexible and ALM-friendly workflow.

Powerful Data Manipulation Capabilities in X++

One significant strength of X++ is its rich and integrated data manipulation capabilities within the ERP system. We’ve touched on this in various ways, but let’s summarize why X++ offers a powerful (instead of “robust”) data-handling experience out-of-the-box:

  • Native SQL Integration: X++ allows you to perform CRUD (Create, Read, Update, Delete) operations using language constructs instead of external SQL. The select, insert, update, and delete statements/methods in X++ cover most data operations. For example, to update records en masse, you can use an update_recordset which translates into a single SQL UPDATE statement affecting multiple rows. Similarly, insert_recordset lets you insert many rows at once by selecting from another source in one go. These set-based operations are efficient and reduce the need for writing loops in code to handle multi-row operations.
  • Transactional Support: X++ handles database transactions via the ttsBegin / ttsCommit statements. This ensures that a series of operations can be committed or rolled back atomically. The language automatically ties into SQL transaction management, and it also auto-aborts on exceptions (as mentioned, any exception triggers a rollback). This makes it easier to maintain data integrity; you don’t have to manually manage SQL transactions or worry about leaving a transaction open – X++ and the runtime manage that. Furthermore, the platform enforces transactional integrity and even has a built-in timeout for long-running SQL statements (with exceptions if a query exceeds certain time limits).
  • Set-Based Operations and Caching: X++ encourages set-based operations (doing things in one query if possible) which is generally more performant. It also has mechanisms like record caching at different scopes (so that repeated selects of the same data don’t always hit the database). For instance, selecting by a primary key may pull from cache if available. There are keywords like firstOnly which, if used cleverly with indexes and caching, can sometimes result in retrieval from a cache rather than the database (though one must understand the caching behavior). There’s even a while select construct which handles iterative selection with automatic fetching of the next record via the next keyword behind the scenes – simplifying cursor-like operations.
  • Security and Data Consistency: Because X++ queries run within the application, they respect the security layer (table permissions, record-level security) and any business logic on the data. For example, if a table has a method override on validateWrite() (which runs during insert/update to validate data), that will be invoked automatically during X++ operations. If an external program were to write to the database, it would bypass those checks. X++ data manipulation is therefore safer and more consistent with business rules. It’s not just about retrieving data, but doing so in a context that ensures the rules of the ERP are applied.
  • Specialized APIs for Data: Beyond the core language statements, X++ in D365 FO provides additional frameworks like the SysDa API which is an abstraction for data access that can be used in more dynamic scenarios (for example, building queries in code without using hardcoded table names, useful in extensibility scenarios). It also provides classes for managing sets of records (RecordInsertList, RecordSortedList) which can batch up operations and then push them to the database in one call. These give developers multiple tools for different needs – either stay in pure X++ syntax or use classes to manipulate data more programmatically.

In a nutshell, X++’s data manipulation features are comprehensive and deeply integrated into the language. This is a major advantage when working within D365 FO: a developer can perform complex data tasks with relatively few lines of code, and trust that those operations are optimized and secure. For instance, to copy data from one table to another, an X++ developer might use one insert_recordset statement that does a select from source and inserts into target – all in one round trip to the database. A C# developer would have to either load the data into memory and loop insert, or craft a SQL statement manually and execute it via ADO.NET. Thus, X++ provides a productive and high-level way to handle data that’s well-suited to enterprise needs. Replacing the word “robust,” we could say X++ offers powerful native data manipulation capabilities, which allow developers to interact with the application’s data model efficiently and safely.

Extending Functionality: X++ Extensions vs Traditional Inheritance

One concept that new D365 FO developers must grasp is the difference between how we extend base functionality in X++ versus how one might do it in a standard object-oriented language like C# or Java. In classical OOP (Java, C#), if you want to extend or modify the behavior of a base class, you typically use inheritance: you create a subclass that inherits from the base class, override some virtual methods, and maybe substitute the subclass in place of the original where needed. You might also have the option of injecting new behavior via design patterns or, in C#, using extension methods (which are a way to add static methods that act like additional instance methods). But crucially, in standard OOP, you don’t get to actually change the original class without editing its code – you either subclass it or use composition.

In X++, prior to D365 FO, one could override methods on existing classes by overlayering (basically copy the class to a higher layer and modify it), which was akin to editing the class. As we discussed, that approach is replaced by extensions in D365 FO. There are two primary ways to extend functionality now: event handlers and class extensions (augmentation).

  • Event handlers (pre/post handlers): Many events are exposed by the system (or can be custom defined) that allow you to attach your code to run before or after a “base” method executes. For example, if we want to run logic every time the validateField method of a table is called, we can subscribe to the “onValidatedField” event. These events are implemented as multicast delegates in X++. Subscribing doesn’t require altering the original method; you just declare an event handler method in your class and decorate it or register it to run at the designated event point. In Java or C#, the equivalent would typically be having the base class call hooks or using an observer pattern – but if the base class wasn’t built for extensibility, you’d be stuck. In X++, Microsoft has added a lot of hooks (events and delegates) in base code explicitly to allow extension.
  • Class extensions (augmentation): This is a unique feature in X++. A class extension is essentially a way to add new methods (or variables) to an existing class without subclassing it. You create a new class with the same name as the target class, followed by the suffix _Extension. By doing so, at compile time, the system will treat your methods as if they were part of the original class. For example, if there is a standard class CustInvoiceJour, and you want to add a new method calculateDiscount() to it, you can create a class named CustInvoiceJour_Extension in your model and implement a method public void calculateDiscount() { ... }. That method can now be called on any CustInvoiceJour object at runtime, just like built-in methods. This is somewhat analogous to C#’s partial classes (where a class’s definition can be split across files) combined with extension methods – except these are true instance methods and can even access protected members of the class (since they are considered part of the class definition). Java has nothing quite like this; you’d have to either subclass or use composition patterns. In X++, class extensions are also sometimes referred to as augmented classes. They let you add behavior without touching the base class code or needing the base class to invoke your code explicitly.
  • No base code modification: With extension classes and event handlers, you never modify the original source of Microsoft’s objects. Instead, you’re either augmenting the object or reacting to its events. This is critical for upgrades – your changes are in your own model, separate from the base, so when Microsoft updates the base, your extensions remain and ideally continue working (unless the base change is fundamental, in which case you may need to adjust your extension, but you still won’t be merging code line-by-line as in overlayering days).

Now, why is it important to understand this difference? If you come from a Java or C# background, your instinct when you want to change behavior might be to subclass a class and then somehow use your subclass in place of the original. In D365 FO, many core classes are marked sealed (final) specifically to prevent subclassing; Microsoft wants you to use the extension model. If you tried the classical approach (e.g., inherit and override), you often can’t because the class or method might not allow it, or even if you do, the application code is not designed to call your subclass. Instead, the correct approach is to either augment the class (add methods that will be called from somewhere in your code or via events) or handle events to influence execution.

For example, suppose you want to change how the system validates a sales order. In Java, you might subclass the SalesOrder class and override a validate method. But in D365 FO, you might subscribe to the SalesOrder’s OnValidated event or add a post-event handler after the standard validation runs, to inject your logic. Or you might augment the SalesOrder class to add a new method that the system will call (maybe via an event or via some configuration). The framework is set up such that these extension points are recognized.

Understanding extensions vs traditional inheritance helps you try and avoid attempts at unsupported customizations. If someone tried to directly edit a standard class or bypass the extension system, not only would it be unsupported, but the system’s packaging wouldn’t allow it (you’d get compile errors for overlayering if the model is sealed). It’s also key to grasp this for debugging and design: an event handler doesn’t alter base code flow; it runs alongside it. A class augmentation doesn’t change base logic; it adds to it. This means when reading code or troubleshooting, you need to remember that what’s executed at runtime might be a combination of base and extension code.

To contrast with Java/C# typical extension: In those languages, if you control the base code, you might simply add or modify code directly. If not, you might inherit or use patterns. X++ pushes developers to think in terms of non-intrusive customization – which is somewhat akin to using aspects or dependency injection in other contexts. The upside is isolation of custom code; the downside can be a bit more complexity in tracing logic (since it’s spread between base and extension).

To give a practical scenario: In AX 2012, one might override the insert() method of CustTable to add some custom behavior during customer creation. In D365 FO, CustTable’s insert might be sealed, so instead you either handle the CustTable.OnInserted event or use a Chain-of-Command (CoC) pattern. Chain of Command is actually another form of extension where you wrap a method call with a next call to base – it’s syntactic sugar Microsoft introduced to let you call the base method and run code before/after it, without modifying the base. This is considered a type of class extension as well, and is often used for extending business logic where you need to change what a method does but still call the original implementation at some point. CoC wasn’t explicitly asked in the question, but it’s part of how extension classes work.

X++ extension classes vs traditional extensions differ in that X++ allows augmenting an existing class in place (like partial classes at runtime), whereas traditional OOP requires either altering the class or subclassing it. The X++ approach is important for maintaining upgradability and respecting the sealed nature of the base application. Understanding this difference ensures that developers use the correct patterns in D365 FO and do not attempt unsupported modifications. Embracing the extension model (via class augmentation and event subscribers) is crucial to successfully implementing custom requirements in Finance & Operations without compromising the system’s ability to receive continuous updates.

X++ Developer Takeaway

X++ remains a powerful and specialized high-level language at the heart of Dynamics 365 Finance & Operations. It combines familiar programming constructs with unique ERP-oriented features – truly an object-oriented language that is deeply aware of the application context and data model. We explored how X++ syntax and fundamentals mirror those of languages like C# and Java, making it accessible to experienced developers, while its integrated SQL-like capabilities set it apart by streamlining data access inside the ERP. We also looked at the evolution of X++ and its ecosystem: the move to Visual Studio, .NET IL compilation, and the extension customization paradigm have modernized the development experience and made maintaining custom code easier in the long run.

Comparing X++ to other languages, we went ahead and made note that it stands out well as a high-level, domain-specific tool – so not  really something you’d use to build a general web app, but instead might be exceptionally well-tuned for business application logic. The lack of third-party tooling support like SonarQube is a reminder that X++ lives in a niche, but Microsoft provides equivalent guidance through best practice checks and patterns to ensure code quality. Understanding the file-based nature of X++ in D365 (with code in XML) gives insight into how the platform manages and deploys customizations in a source-controlled, cloud-friendly way.

The concept of extensions in X++ underscores a shift in the overarching philosophy: rather than modifying standard code, we extend it instead – a kind of practice that in many ways could inform how one approaches customizations in any system, and not just Dynamics 365. The difference in extension approaches between X++ and typical languages highlights the importance of designing for maintainability and upgradeability.

X++ programming in D365 FO empowers developers to write rich business logic that can directly manipulate data and respond to user actions within the robust framework of an enterprise application. Its high-level, integrated nature means developers can focus on solving business problems (“logic in terms of invoices, customers, and ledgers”) instead of plumbing (“connecting to a DB and parsing results”). And with the improvements introduced in the Dynamics 365 era, X++ development is more efficient, the resulting code runs faster, and customizations coexist more harmoniously with the base product. All these factors make X++ a uniquely potent language for its intended domain, even as one must navigate its proprietary aspects and tooling. By adhering to the recommended practices (like using Visual Studio and the extension model) and leveraging X++’s strengths (like its data-awareness and application integration), developers can create robust (and maintainable) solutions on the Dynamics 365 platform.

 

Have a Question ?

Fill out this short form, one of our Experts will contact you soon.

Call Us Today For Your Free Consultation