As an X++ developer, I am very used to using ‘while select’ statements to loop through records stored in a database. However, as a C# developer, I often loop through lists of class objects. In this article, learn how to add values to a D365 list and loop through it. Additionally, learn how to add values at the beginning and end of a list. As well as combine two lists together.
Types of Collection Classes
Before going into the details of a D365 List, remember that the List class is one of the collection classes.
As an overview, there are five different types of D365 collection classes defined in the base Microsoft code. To explain, these special types of classes provide additional functionality that helps developers. They help store, find, and iterate through lists of objects. They each work a little bit differently.
- Array – The Array class must hold values of the same data type. They are often used to hold multiple objects or records.
- List – Used to store sequential values, which are all of the same data type. There are methods to make it easy to add values at the beginning or the end of the list.
- Set – Every value added to a set must be of the same data type. However, values are not stored in the order in which you add them. Instead, they are optimized for checking if the same value already exists in the set. If you try to add a value that already exists, the duplicate value will not be added. This class is great when you are working with a unique set of values.
- Map – Used to store a unique key and an associated value. Similar to a Dictionary in C#. All keys must have the same data type. Additionally, all values must have the same data type.
- Struct – Similar to a class, these objects store multiple values relating to a specific entity together. For example, you might store a customer’s name, birthday, and address as a single item. A struct uses string indexes. A container, which is similar, uses numeric indexes.
To learn more, click on the above links for a detailed explanation of each D365 collection class.
Setup
To test the code shown in the sections below, first create a new project in Visual Studio.
Second, create a runnable class (job). To do this, right-click on the project and select Add>New Item. Then select ‘Runnable Class (Job)‘, and give the job a name. I named mine tutorialList.

Third, copy the code sections below into the ‘main‘ method.

Fourth, right-click on your runnable class (job) and select ‘Set as Startup Object‘. This will enable it to run when you click the ‘Start‘ button.

Finally, click the ‘Start‘ button in Visual Studio. This will first build the code. Then, if there are no errors, this will open a browser, navigate to the D365 runnable class (job), and run the code. View the info message output to see the results.

Defining A List
First, when a D365 List is created, the data type of the values stored in the list is specified. This cannot be changed.
// Create a list of integers
List list = new List(Types::Integer);
Notice, the Types enum is passed into the constructor. These are the various options that the Types enum has.
- AnyType
- BLOB
- Class
- Container
- Date
- Enum
- Guid
- Int64
- Integer
- RString
- Real
- Record
- String
- Time
- UserType
- UtcDateTime
- VarArg
- VarString
- void
Typically, I always pass in a Types enum value. However, you can use a function to get the value from an Extended Data Type. See this example.
// Create a list of whatever data type the SalesId extended data type uses. Hint: It is of type String.
List list = new List(extendedTypeNum(SalesId));
// The above line would be the same as this for the Extended Data Type 'SalesId'.
List listString = new List(Types::String);
Add Values To A List
Second, after instantiating a D365 list, the next step is to add values to the list. Use the ‘addEnd‘ method to add values to the end of the list. See this example where integers are added to a list.
// Create a list of integers
List list = new List(Types::Integer);
//Add numbers to the list.
list.addEnd(1);
list.addEnd(2);
list.addEnd(3);
Note, when using ‘addEnd‘, the values will be stored in the D365 list in the order you add them
Similarly, use the ‘addStart‘ method to add values to the beginning of the list.
// Create a list of integers
List list = new List(Types::Integer);
//Add numbers to the end of the list.
list.addEnd(1);
list.addEnd(2);
list.addEnd(3);
//Add numbers to the beginning of the list.
list.addStart(0);
As seen, using the built-in method ‘addStart‘ makes it way easier to add values at the beginning of a list, compared to if you had to write code to do this yourself.
Loop Through A List
Third, now that there are values in the D365 list, loop through and print out the values. In order to loop through a list, we need to use a class named ListEnumerator. See the example below.
// Create a list of integers
List list = new List(Types::Integer);
ListEnumerator listEnumerator;
int value;
//Add numbers to the end of the list.
list.addEnd(1);
list.addEnd(2);
list.addEnd(3);
//Add numbers to the beginning of the list.
list.addStart(0);
//Get the list enumerator from the list object.
listEnumerator = list.getEnumerator();
while (listEnumerator.moveNext())
{
value = listEnumerator.current();
info(strfmt("%1",value));
}
Start by declaring a variable of type ListEnumerator. Next, call the method ‘getEnumerator()‘ on the list to get an instantiated list enumerator. Set it to the list enumerator variable.
Then, create a ‘while‘ loop. Inside the while loop, call the method ‘moveNext()‘ on the list enumerator. If there is a next value in the list, it will move to it and return true. If there are no more values in the list, this method will return false. Notice, this will cause the inside of the while loop to no longer be called.
Next, call the method ‘current()‘ to get the value out of the list and store it in a variable. In this case, we know the values are all integers.
Finally, use the ‘strfmt()‘ method to convert the value into a string and print it out as a message.
The result should look like this, with the most recent message on the top.

Scroll down to see the first message, 0.

Append List and Merge Lists
Additionally there are other methods that exist on the D365 list class that are helpful to a developer.
For example, if you have a list and you want to add the contents of a second list to the end of the first, you can do this using the ‘appendList‘ method.
List list1 = new List(Types::Integer);
List list2 = new List(Types::Integer);
int i;
for(i=1; i<6; i++)
{
List1.addEnd(i);
}
for(i=6; i<11; i++)
{
List2.addEnd(i);
}
list1.appendList(list2);
info(list1.toString());
The results look like this.

Similarly, if you have two lists that you want to combine together, but you wish to keep the original lists unmodified, use the merge method.
List list1 = new List(Types::Integer);
List list2 = new List(Types::Integer);
List combinedList = new List(Types::Integer);
int i;
for(i=1; i<6; i++)
{
List1.addEnd(i);
}
for(i=6; i<11; i++)
{
List2.addEnd(i);
}
combinedList = List::merge(list1, list2);
info(combinedList.toString());
The results look like this.

Count of Values
Furthermore, there may be times you need to know the number of values in a D365 list. Use the ‘elements‘ method to return the number of values in the list.
List list = new List(Types::Integer);
list.addStart(1);
list.addStart(2);
list.addStart(3);
info(strfmt("There are %1 values in the list.", list.elements()));
The result looks like this.

Example
For an example of a D365 list in the base Microsoft code, look at the class AppCopilotAgentTaskTemplateProvider. Interestingly, the code loops through a list of classes, checks to see if the class is accessible to the user, and if so, then adds the class to a second list.

Iterator vs. Enumerator
Interestingly, there are two ways of looping through a D365 List. Use the ListEnumerator class or use the ListIterator class.
As a best practice, you should use the ListEnumerator. It requires less code and performs slightly better.
ListEnumerators cannot be modified while traversing through the values. Whereas a ListIterator can insert or delete elements during traversal. Therefore, there may be rare cases when you need to use a ListIterator. See this example for the different methods involved.
List list = new List(types::Integer);
ListIterator listIterator;
// Add some elements into the list.
list.addStart(1);
list.addStart(2);
list.addStart(3);
// Create a list iterator to traverse the values.
listIterator = new ListIterator(list);
// Prints 1, 2, 3.
while (listIterator.more())
{
info(strfmt("%1",listIterator.value()));
listIterator.next();
}
Notice, the ListIterator uses the method more(), instead of moveNext() in the while loop. Additionally, the more() method only returns whether there are more elements in the list. It does not move to the next value in the list. Therefore, a call to next() is needed inside of the loop to move to the next value. This approach requires one extra line of code compared to ListEnumerator.
Pack and Create
Moreover, a D365 list can be packed into a container object and unpacked. This is helpful when working with certain batch jobs that have existing functionality dependent on containers. See this example.
List list = new List(Types::Real);
List newList;
container c;
// Fill list
list.addEnd(1.61803);
list.addEnd(3.14159);
// Pack the list into a container
c = list.pack();
// Create a new list from the packed list
newList = List::create(c);
Microsoft Documentation
In order to learn more about how to use a D365 list, check out the Microsoft documentation here. On this page, you can see all of the available helper methods on the class.
I also want to thank Tim Fluharty, whom I am learned a great deal from, and who provided information for this series of articles.
Conclusion
Although using lists is somewhat less common in X++ and Microsoft Dynamics 365, they remain very useful in the right circumstances. They are essential to know so that you can understand them when you see them in the base code. They are very helpful for keeping track of values and help make your code safer, faster, and easier to read.
Leave a Reply