Vous êtes sur la page 1sur 33

Microsoft Dynamics AX 2009

X++, C# Comparison: Hello World


This topic compares the simplest X++ program to its counterpart in C#. X++ to C# Comparisons The following sections describe some basic similarities and differences between X++ and C#. Similarities The following X++ features are the same for C#:

Single line (//) and multi-line (/* */) comments.

== (equal) operator for determining whether two values are equal. != (not equal to) operator for determining whether two values are not equivalent. + (plus sign) operator for string concatenation.

Differences The following table lists X++ features that are different in C#. Features Declarations X++ All declarations must be at the start of the method, before any X++ statements. C# Declarations can occur anywhere in the method. Comments Both languages permit multiple variables of the same type to be listed together in one declaration. Both languages allow you to assign an initial value in the declaration statement. The X++ compiler requires the extra semicolon. For more information, see X++ Standards: Using Semicolons The syntax structure regarding curly braces and parentheses is exactly the same between X++ and C#.

Extra semicolon (;)

An extra semicolon (;) is needed after the last declaration, and before any statements, in each method. The if statement accepts any type of expression that it can automatically convert to a Boolean. Common examples include an int for which 0 means false, or an object for which null means false. A literal string can be delimited by either of the following: A pair of double quotation mark (") characters.

Not needed in C#.

if and elseconditional
statements

The if statement requires a Boolean expression.

Literal string

A literal string must be delimited by a pair of double quotation mark (") characters.

A pair of single quotation mark (') characters.

For X++, the double quotation mark characters are usually used to delimit strings. However, it is convenient delimit a string with single quotation mark characters when your string must contain a double quotation mark character. For more information about X++ data types, see Primitive Data Types.

char type

There is no char or character type in X++. You can declare a str of length one, but it is still a string:

str 1 myString = "a";

There is a char in C#. You cannot pass a char as the parameter to a method that inputs a string parameter, although you can first explicitly convert the char to a string. For a command line C# program, messages can be delivered to the console. Common methods include the following:

Output of messages

X++ delivers messages to the user in the Infolog window. Common methods include the following: The print statement:

Console.Out.WriteLine Console.Error.WriteLine

static methods on the

Global class: Global::info Global::warning Global::error

The print statement is not a function nor a method. Recommended use would be print mystring; rather than print(mystring);. A pause; statement is always useful shortly after a print statement. The print statement is convenient for testing because it automatically converts int and other primitive values to strings for display. For more information, see Print Statements. The Global class has special

recognition in the X++ compiler. The info method can be called without including the Global:: prefix. For more information, see, Global::info Method. X++ and C++ Samples This section contains two simple code samples. One sample is written in X++, and the other is in C#. Both samples achieve the same result. The following X++ features are demonstrated:

// single line comment /* */ multi-line comment


The required extra semicolon (;)

if statement == operator != operator + operator to concatenate strings Global::info for message output, with and without the Global:: prefix Global::error for message output
The use of single and double quotation characters (' and ") as string delimiters. Note The best practice is to use double quotation marks for any string that might be displayed to the user.

X++ Sample This X++ code sample is in the form of a job. There is a node titled Jobs in the Application Object Tree (AOT). This sample can be added under the Jobs node, and then the job can be run. Copy Code

static void JobRs001a_HelloWorld(Args _args) { ; if (1 == 1) { // These two info() calls are identical to the X++ compiler. // The second form is the one typically used in X++. Global::info("Hello World, 1."); info('Hello World, 2.'); } if (1 != 1) { error("This message will not appear."); } else { // These two methods are also from the Global class. // The '+' operator concatenates two strings. warning("This is like info," + " but is for warnings, 3."); error("This is like info," + " but is for errors, 4."); } }
Output Here is the actual output from the Infolog window:

Message (09:49:48) Hello World, 1. Hello World, 2. This is like info, but is for warnings, 3. This is like info, but is for errors, 4.
C# Sample The following C# program is a rewrite of the previous X++ program. The differences between X++ and C# are highlighted by commenting out the X++ lines, and replacing them with the C# syntax. Copy Code

using System; class Pgm_CSharp { static void Main( string[] args ) { new Pgm_CSharp().Rs001a_CSharp_HelloWorld(); } void Rs001a_CSharp_HelloWorld() { if (1 == 1) { Console .Out .WriteLine( "Hello World, Explicit .Out , 1."); Console .WriteLine( "Hello World, Implicit default to .Out , 2."); } if (1 != 1) { Console .Error .WriteLine( "This message will not appear."); } else { Console .Error .WriteLine(".Error is like .Out," + " but can be for warnings, 3."); Console .Error .WriteLine(".Error is like .Out," + " but is for errors, 4."); } } }
Output Here is the actual output to the C# console:

Hello World, Explicit .Out , 1. Hello World, Implicit default to .Out , 2. .Error is like .Out, but can be for warnings, 3. .Error is like .Out, but is for errors, 4.

Microsoft Dynamics AX 2009

X++, C# Comparison: Loops


This topic compares the loop features between X++ and C#. X++ to C# Comparisons Similarities The following features are the same in X++ and C#:

Declarations for variables of the int primitive data type. Declarations for other primitive types are almost the same, but the types might have different names. while statement for loops. break statement to exit a loop. continue statement to jump up to the top of a loop.

<= (less than or equal) comparison operator.

Differences The following table lists X++ features that are different in C#. Features The for statement. X++ The for statement is available for loops. C# The C# for statement is slightly different from for in X++. Discussion In C# you can declare the counter integer in the for statement. But in X++ the counter must declared outside the for statement. The following lines of code are the same in both languages:

++ increment
operator.

An ++ increment operator is available in X++. But an int variable that is decorated with ++ can only be used as a statement, not as an expression. For example, the following lines of X++ code would not compile:

The C# ++ operator is more flexible than in X++.

++ myInteger; myInteger++;
But the following lines of code have a different effect from each other, and are valid only in C#:

int age=42; print age++;


However, the following lines of X++ code would compile:

yourInt = ++myInt; yourInt = myInt++;

int age=42; age++; print age;


modulo operator. In X++ the modulo operator is mod. In C# the modulo operator is %.

The symbols for the modulo operator are different, but their behavior is the same in both languages. In X++ you continue by clicking an OK button on a modal dialog box. In C# you continue by pressing any keyboard on the keyboard. The X++ print function is used only when you test. An X++ program that uses print almost always uses the pause statement somewhere later in the code. For production X++ code, use the Global::info Method instead of print. The strfmt function is often used together with info. There is no reason to use pause after info. The statements each produce a short tone.

Temporarily suspend a console program that has already begun. Display a message.

The pause statement.

In C#, a command line program can be paused by the following line of code:

In X++, the print statement displays a message in the Print window.

Console.In.Read();
In C# a message can be displayed on the console by the following line of code:

Console.WriteLine();

Make a sound.

The beep function makes a sound that you can hear.

In C# a sound that you can hear is issued by the following line of code:

Console.Beep();

Print and Global::info The X++ code samples in this topic use the print function to display results. In X++ you can use the print statement can display any primitive data type without having to call functions that convert it to a string first. This makes print useful in quick test situations. Generally the Global::info method is used more often than print. The info method can only display strings. Therefore the strfmt function is often used together with info.

A limitation of print is that you cannot copy the contents of the Print window to the clipboard (such as with Ctrl+C). Global::info writes to the Infolog window which does support copy to the clipboard. Example 1: The while Loop The while keyword supports looping in both X++ and C#. X++ Sample of while Copy Code

static void JobRs002a_LoopsWhile(Args _args) { int nLoops = 1; ; while (nLoops <= 88) { print nLoops; pause; // The X++ modulo operator is mod. if ((nLoops mod 4) == 0) { break; } ++ nLoops; } beep(); // Function. pause; // X++ keyword. }
Output The output in the X++ Print window is as follows:

1 2 3 4
C# Sample of while Copy Code

using System; public class Pgm_CSharp { static void Main( string[] args ) { new Pgm_CSharp().Rs002a_CSharp_ControlOFlowWhile(); } void Rs002a_CSharp_ControlOFlowWhile() { int nLoops = 1; while (nLoops <= 88) { Console.Out.WriteLine( nLoops.ToString() ); Console.Out.WriteLine( "(Press any key to resume.)" ); // Paused until user presses a key. Console.In.Read(); if ((nLoops % 4) == 0) break; ++ nLoops; } Console.Beep(); Console.In.Read(); } }
Output The console output from the C# program is as follows:

[C:\MyDirectory\] >> Rosetta_CSharp_1.exe 1 (Press any key to resume.) 2 (Press any key to resume.) 3 (Press any key to resume.) 4 (Press any key to resume.)
Example 2: The for Loop The for keyword supports looping in both X++ and C#. X++ Sample of for In X++ the counter variable cannot be declared as part of the for statement. Copy Code

static void JobRs002a_LoopsWhileFor(Args _args) { int ii; // The counter. ; for (ii=1; ii < 5; ii++) { print ii; pause; // You must click the OK button to proceed // beyond a pause statement. // ii is always less than 99. if (ii < 99) { continue; } print "This message never appears."; } pause; // X++ keyword. }
Output The output in the X++ Print window is as follows:

1 2 3 4
C# Sample of for Copy Code

using System; public class Pgm_CSharp { static void Main( string[] args ) { new Pgm_CSharp().Rs002a_CSharp_ControlOFlowFor(); } void Rs002a_CSharp_ControlOFlowFor() { int nLoops = 1, ii; for (ii = 1; ii < 5; ii++) { Console.Out.WriteLine(ii.ToString());

Console.Out.WriteLine("(Press any key to resume.)"); Console.In.Read(); if (ii < 99) { continue; } Console.Out.WriteLine("This message never appears."); } Console.Out.WriteLine("(Press any key to resume.)"); Console.In.Read(); } }
Output The console output from the C# program is as follows:

1 (Press any key to resume.) 2 (Press any key to resume.) 3 (Press any key to resume.) 4 (Press any key to resume.) (Press any key to resume.)

Microsoft Dynamics AX 2009

X++, C# Comparison: String Case and Delimiters


This topic compares the treatment of strings with mixed casing in X++ and C#. It also explains the string delimiters that are available in X++. X++ to C# Comparisons There are similarities and differences in how strings are delimited in X++ and C#. Similarities The following X++ features are the same as in C#:

The backslash (\) is the escape operator for string delimiters. The at sign (@) nullifies the escape effect of the backslash when the at sign is written immediately before the open quotation mark of a string. The plus sign (+) is the string concatenation operator.

Differences X++ features that are different in C# are listed in the following table. Feature X++ Insensitive: the == operator is insensitive to differences in string casing. In X++ you can use either the single (') or double (") quotation mark as the string delimiter. Note Usually the best practice is to use double quotation marks for strings that might be displayed to the user. However, it is convenient to delimit a string with single quotation marks when a double quotation mark is one of the characters in the string. X++ has a string data type (str), but no character type. C# In C#, the == operator is sensitive to differences in string casing. In C# you must use the double quotation mark as the string delimiter. This refers to the type System.String. Comments In X++ you can use the strCmp Function for case sensitive comparisons between strings. In X++ and C# you have the option of embedding a delimiter in a literal string and escaping it with \. In X++ you also have the alternative of embedding single quotation marks in a string that is delimited by double quotation marks (or the reverse), without having to use the escape.

==
comparison operator String delimiters

Character delimiters

In C# you must use the single quotation mark as the character delimiter. This refers to the type System.Char.

In the .NET Framework, a System.String of length one is a different data type than a System.Char character.

Example 1: Case Sensitivity of the == Operator The == and != operators are case insensitive in X++, but are case sensitive in C#, as is illustrated by the following example. X++ C# Comments Different case comparisons between X++ and C#.

"HELLO" == "hello"
True in X++.

"HELLO" == "hello"
False in C#.

Example 2: The + String Concatenation Operator The + and += operators are used to concatenate strings in both X++ and C#, as is shown by the examples in the following table. X++ C# (Same as for X++.) Comments In both X++ and C#, the behavior of the + operator depends on the data type of its operands. The operator concatenates strings, or adds numbers.

myString1 = "Hello" + " world";


Result is equality:

myString1 == "Hello world" mystring2 = "Hello"; myString2 += " world";


Result is equality: (Same as for X++.) In both X++ and C#, the following statements are equivalent:

a = a + b; a += b;

myString2 == "Hello world"


Example 3: Embedding and Escaping String Delimiters Either single or double quotation marks can be used to delimit strings in X++. The escape character (\) can be used to embed delimiters in a string. These are illustrated in the following table. X++ C# (Same as for X++.) Comments The escape character enables you to embed string

myString1 =

"He said \"yes\".";


Result: He said "yes".

delimiters inside strings.

myString2 = 'He said "yes".';


Result: He said "yes".

C# syntax does not allow for single quotation marks to delimit strings.

For strings that may be seen by the user, it is considered a best practice to use the escape character instead of the single quotation marks as shown in the example. In X++, the single quotation marks are not treated as delimiters unless the string starts with a single quotation mark delimiter. In C# the single quotation mark has no special meaning for strings, and it cannot be used to delimit strings. In C# the single quotation mark is the required delimiter for literals of type System.Char. X++ has no character data type. X++ has no data type that corresponds to System.Char in the .NET Framework. An X++ string that is limited to a length of one is still a string, not a character data type.

myString3 = "He said 'yes'.";


Result: He said 'yes'.

(Same as for X++.)

str myString4 = 'C';


Here the single quotation is a string delimiter.

char myChar4 = 'C';


Here the single quotation mark is a System.Char delimiter, not a System.String delimiter.

Example 4: Single Escape Character Examples that illustrate the single escape character in either the input or the output are shown in the following table. X++ C# A literal string in C# cannot contain the two character sequence of escape followed by a space, such as "\ ". A compiler error occurs. (Same as for X++.) Comments When the X++ compiler encounters the two character sequence of "\ ", it discards the single escape character. In a pair of escape characters, the first negates the special meaning of the second.

myString1 = "Red\ shoe";


Result: Red shoe

myString2 = "Red\\ shoe";


Result: Red\ shoe

Microsoft Dynamics AX 2009

X++, C# Comparison: Array Syntax


This topic compares array syntax between X++ and C#. X++ to C# Comparisons There are similarities and differences in the features and syntax for arrays in X++ versus C#. Similarities Overall there is much similarity in the syntax and treatment of arrays in X++ and C#. However there are many differences. Differences The following table lists areas in the [] syntax for arrays that are different for X++ and C#. Category X++ C# An array is declared with square brackets appended to the data type. Comments

Declaration An array is declared with square brackets appended to the variable name.

int myInts[]; // X++


Note An X++ array cannot be a parameter in a method.

int[] myInts; // C#
Declaration The array syntax supports only primitive data types, such as int and str. The syntax does not support classes or tables. Declaration X++ is limited to single dimension arrays (myStrings[8]). The array syntax supports primitive data types and classes. In X++ you can use the Array class for an array of objects.

C# adds support for multidimensional arrays (myStrings[8,3]) and for jagged arrays (myStrings[8][3]).

In X++ you cannot have an array of arrays. However, there is advanced syntax for limiting the amount of active memory that a large array can consume, which looks like the multi-dimensional syntax in C#: int intArray[1024,16];. For more information, see Swapping Arrays to Disk. X++ does have an Array class, but its underlying mechanism differs from arrays created by using the [] syntax. In C# all arrays use the same underlying mechanism, regardless of whether [] syntax of the System.Array class is used in your code.

Declaration In X++ an array is a special construct but it is not an object.

In C# all arrays are objects regardless of syntax variations.

Length

In X++ the length of a static sized array is determined in the declaration syntax.

In C# the size of an array is determined when the array object is constructed.

When you use the [] declaration syntax in X++, no more preparation is needed before you assign values to the array. In C# you must declare and then construct the array before assigning to it.

Length

An X++ array can have a dynamic length that can be increased even after population has begun. This applies only when the array is declared without a number inside the []. Performance might be slowed if the length of the dynamic array is increased many times.

In C# the length of an array cannot be changed after the length is set.

In the following fragment of X++ code, only the myInts array is dynamic and can increase in size.

int myInts[]; int myBools[5]; ; myInts[2] = 12; myInts[3] = 13; myBools[6] = 26; //Error

Length

You can get the length of some arrays by using the dimOf function. Array indexing is 1 based.

C# arrays are objects that have a Length property.

No comments.

Indexing

Array indexing is 0 based.

mtIntArray[0] would cause an error in


X++.

Constant

In X++ a constant value is best

In C# you can decorate

X++ has no const keyword. C# cannot assign

achieved by using the #define precompiler directive.

your variable declaration with the keyword const, to achieve a constant value.

values to variables that are created by its #define precompiler directive.

X++ and C# Samples The following code samples show how arrays of primitive data types are handled. The first sample is in X++, and the second sample is in C#. Both samples achieve the same results. X++ Sample Copy Code

static void JobRs005a_ArraySimple(Args _args) { #define.macroArrayLength(3) // Static length. str sSports[#macroArrayLength]; // Dynamic length, changeable during run time. int years[]; int xx; ; Global::warning("-------- SPORTS --------"); sSports[#macroArrayLength] = "Baseball"; for (xx=1; xx <= #macroArrayLength; xx++) { info(int2str(xx) + " , [" + sSports[xx] + "]"); } warning("-------- YEARS --------"); years[ 4] = 2008; years[10] = 1930; for (xx=1; xx <= 10; xx++) { info(int2str(xx) + " , " + int2str(years[xx])); } }
Output The output to the Infolog is as follows:

Message (14:16:08) -------- SPORTS -------1 , [] 2 , [] 3 , [Baseball] -------- YEARS -------1 , 0 2 , 0 3 , 0 4 , 2008 5 , 0 6 , 0 7 , 0 8 , 0 9 , 0 10 , 1930
C# Sample Copy Code

using System; public class Pgm_CSharp { static public void Main( string[] args ) { new Pgm_CSharp().Rs005a_CSharp_ArraySimple(); }

private void Rs005a_CSharp_ArraySimple() { const int const_iMacroArrayLength = 3; // In C# the length is set at construction during run. string[] sSports; int[] years; int xx; Console.WriteLine("-------- SPORTS --------"); sSports = new string[const_iMacroArrayLength]; sSports[const_iMacroArrayLength - 1] = "Baseball"; for (xx=0; xx < const_iMacroArrayLength; xx++) { Console.WriteLine( xx.ToString() + " , [" + sSports[xx] + "]" ); } Console.WriteLine("-------- YEARS --------"); // In C# you must construct the array before assigning to it. years = new int[10]; years[ 4] = 2008; years[10 - 1] = 1930; for (xx=0; xx < 10; xx++) { Console.WriteLine( xx.ToString() + " , [" + years[xx].ToString() + "]" ); } } } // EOClass
Output The output from the C# program to the command line console is as follows:

-------- SPORTS -------0 , [] 1 , [] 2 , [Baseball] -------- YEARS -------0 , [0] 1 , [0] 2 , [0] 3 , [0] 4 , [2008] 5 , [0] 6 , [0] 7 , [0] 8 , [0] 9 , [1930]

Microsoft Dynamics AX 2009

X++, C# Comparison: Collections


Microsoft Dynamics AX provides the X++ List collection class. The .NET Framework that is used in C# has a similar class named System.Collections.Generic.List. Comparing the Use of the List Classes The following table compares methods on the X++ List class to the methods on System.Collections.Generic.List from the .NET Framework and C#. Feature Declaration of collection X++ C# Discussion The X++ declaration does not include the type of elements to be stored. In X++ the

List myList;

List<string> myList;

Declaration of iterator

ListIterator iter; ListEnumerator enumer;

IEnumerator<string> iter;

ListIterator object
has methods that can insert and delete items from the List. The X++ ListEnumerator cannot modify the contents of the List. In X++ the

ListEnumerator object
is always created on the same tier as the List. This is not always true for ListIterator. Obtaining an iterator

new ListIterator (myList) myList.getEnumerator()

myList.GetEnumerator()

In both X++ and C#, the List object has a getter method for an associated enumerator. Information about the type of objects to be stored inside the List classes is given to the constructor in both X++ and C#. Enumerators become invalid after items are added or deleted from the List, in both X++ and C#.

Constructor

new List(Types::String)

new List<string>()

Updating data

Enumerator the enumerator becomes invalid if any items in the

List are added or removed.

Enumerator the enumerator becomes invalid if any items in the List are added or removed.

Iterator the iterator has methods that insert and delete items from the List. The iterator remains valid.

Updating data

In X++ the List class has methods for adding items at the start or end of the list.

In C# the List class has methods for adding members at any position in the list. It also has methods for removing items from any position.

In X++ items can be removed from the List only by an iterator.

Example 1: Declaration of a List The following table displays code examples in X++ and C# that declare List collections. X++ C#

List listStrings ,list2 ,listMerged; ListIterator literator;

using System; using SysCollGen = System.Collections.Generic; SysCollGen.List<string> listStrings ,list2 ,listMerged; SysCollGen.IEnumerator<string> literator;

Example 2: Construction of a List In both languages, the type of items that the collection stores must be specified at the time of construction. For class types, X++ can get no more specific than whether the type is a class (Types::Class). Code examples are in the following table. X++ C#

listStrings = new List( Types::String );

listStrings = new SysCollGen.List<string>();

Example 3: Add Items to a List In both X++ and C#, the collection provides a method for appending an item to the end of the collection, and for inserting an item the start. In C# the collection provides a method for inserting at any point in the collection based on an index value. In X++ a collection iterator can insert an item at its current position. Code examples are in the following table. X++ C#

listStrings.addEnd ("String_BB."); listStrings.addStart ("String_AA.");


// Iterator performs a midpoint // insert at current position.

listStrings.Add ("String_BB."); listStrings.Insert (0 ,"String_AA.");


// Index 7 determines the insertion point.

listStrings.Insert (7 ,"dog");

listIterator.insert ("dog");
Example 4: Iterate Through a List Both X++ and C# have iterator classes that you can use to step through the items in a collection. Code examples are in the following table. X++ C#

literator = new ListIterator (listStrings);


// Now the iterator points at the first item.

literator = listStrings .GetEnumerator();


// Now enumerator points before // the first item, not at // the first item.

// The more method answers whether // the iterator currently points // at an item.

// The MoveNext method both // advances the item pointer, and // answers whether the pointer is // pointing at an item.

while (literator.more()) { info(any2str (literator.value())); literator.next(); }

while (literator.MoveNext()) { Console.WriteLine (literator.Current); }

Example 4b: foreach in C# In C# the foreach keyword is often used to simplify the task of iterating through a list. The following code example behaves the same as the previous C# example.

foreach (string currentString in listStrings) { Console.WriteLine(currentString); }


Example 5: Delete the Second Item The following table contains code examples that delete the second item from the collection. In X++ this requires an iterator. In C# the collection itself provides the method for removing an item. X++ C#

literator.begin(); literator.next();

listStrings.RemoveAt(1);

literator.delete();
Example 6: Combine Two Collections The following table contains code examples that combine the contents of two collections into one. X++ C#

listStrings = List::merge (listStrings ,listStr3);


// Or use the .appendList method:

listStrings.appendList (listStr3);

Microsoft Dynamics AX 2009

X++, C# Comparison: Collections of Keys with Values


Microsoft Dynamics AX provides the Map collection class. The Map collection holds pairs of values, the key value plus a data value. This resembles the .NET Framework class named System.Collections.Generic.Dictionary. X++ to C# Comparisons There are similarities and differences in how a key-value collection is implemented in X++ and C#. Similarities The following list describes similarities between X++ and C# regarding their collections that store key-value pairs:

Both prevent duplicate keys. Both use an enumerator (or iterator) to loop through the items. Both key-value collection objects are constructed with designations of the types that are stored as key and value. Both can store class objects, and are not limited to storing primitives like int.

Differences The following table describes differences between X++ and C# regarding their collections classes that store key-value pairs: Feature Duplicate keys X++ In X++ the Map class prevents duplicate keys by implicitly treating your call to its insert method as an operation to update only the value associated with the key. In X++ the delete method on an iterator object is used to remove an unwanted keyvalue pair from a Map. C# In C# the Dictionary class throws an exception when you try to add a duplicate key. In C# the Dictionary class has a remove method. Comments Duplicate keys are prevented in both languages, although by different techniques.

Delete items

In both languages, an enumerator is made invalid if the collection item count is modified during the life of the enumerator.

Example 1: Declaration of a Key-Value Collection In both languages, the type of items that the key-value collection stores must be specified. In X++ the type is specified at time of construction. In C# the type is specified at both the time of declaration and the time of construction. Code examples are in the following table. X++ C#

Map mapKeyValue; MapEnumerator enumer; MapIterator mapIter;

SysCollGen.Dictionary <int,string> dictKeyValue; SysCollGen.IEnumerator <SysCollGen.KeyValuePair <int,string>> enumer; SysCollGen.KeyValuePair <int,string> kvpCurrentKeyValuePair;

Example 2: Construction of the Collection In both languages, the type of items that the key-value collection stores specified during construction. For class types, X++ can get no more specific than whether the type is a class (Types::Class). Code examples are in the following table. X++ C#

mapKeyValue = new Map (Types::Integer ,Types::String);

dictKeyValue = new SysCollGen.Dictionary <int,string>();

Example 3: Add an Item to the Collection There is almost no difference in how an item is added to a key-value collection, in X++ and C#. Code examples are in the following table. X++ C#

mapKeyValue.insert (xx ,int2str(xx) + "_Value");

dictKeyValue.Add (xx ,xx.ToString() + "_Value");

Example 4: Iterate Through a Key-Value Collection Enumerators are used to loop through the key-value collections in both X++ and C#. Code examples are in the following table. X++ C#

enumer = mapKeyValue.getEnumerator(); while (enumer.moveNext()) { iCurrentKey = enumer.currentKey(); sCurrentValue = enumer.currentValue(); // Display key and value here. }

enumer = dictKeyValue .GetEnumerator(); while (enumer.MoveNext()) { kvpCurrentKeyValuePair = enumer.Current; // Display .Key and .Value properties // of kvpCurrentKeyValuePair here. }

Example 5: Update the Value Associated with a Key The syntax is very different between the two languages for an update of the value associated to a given key. Code examples for the key 102 are in the following table. X++ C#

mapKeyValue.insert (102 ,".insert(), Re-inserted" + " key 102 with a different value.");

dictKeyValue[102] = "The semi-hidden .item property" + " in C#, Updated the value for key 102.";

Example 6: Delete One Item The syntax is very different between the two languages to delete one key-value pair from a collection, while iterating through the collection members. Code examples for the key 102 are in the following table. X++ C#

mapIter = new MapIterator (mapKeyValue); //mapIter.begin(); while (mapIter.more()) { iCurrentKey = mapIter.key(); if (104 == iCurrentKey) { // mapKeyValue.remove would invalidate the iterator. mapIter.delete(); break; } mapIter.next(); }

Microsoft Dynamics AX 2009

X++, C# Comparison: Exceptions


There are some similarities but many differences when we compare exception related behavior between X++ and C#. X++ to C# Comparisons The try, catch, and throw keywords behave the same in X++ and C#. But the types of exceptions thrown and caught are different for the two languages. Similarities Similarities between X++ and C# regarding their exception features include the following:

Both languages have the same try keyword. Both have the same catch keyword. Both enable for a catch statement that does not specify any particular exception. Such a catch statement catches all exceptions that reach it. Both have the same throw keyword.

Differences Exception-related differences between X++ and C# are described in the following table. Feature retry X++ Jumps to the first instruction in the associated try block. For more information, see Exception Handling. C# The functionality of the retry keyword can be mimicked in C# code, but there is no corresponding keyword. Comments Only X++ has a retry keyword. C# has no counterpart. For more information, see X++, C# Comparison: Automated Retry After an Exception. Only C# has a finally keyword. X++ has no counterpart.

finally

There is no finally keyword in X++.

The finally keyword marks a block of code that follows the try and catch blocks. The finally will be executed regardless of whether any exception is thrown or caught. In C# an exception is an instance of the System.Exception base class, or any class that inherits from it. An exception can be contained in the InnerException property of the thrown exception.

Specific exceptions

In X++ an exception is an element of the Exception enum, such as:

Error Deadlock CodeAccessSecurity

In X++ each thrown exception is a value of the Exception enum. For more information, see Exception System Enumeration.

No exception can contain another. Exception message In X++ the message that is created when an exception is raised is available only in the Infolog, and the message is not directly tied to the exception. In C# the message is the Message member of the System.Exception object. In X++ the

Global::error method
is the mechanism that display exception messages in the Infolog. For more information, see Exception Handling. There might be several other differences in the conditions that raise exceptions.

Exception conditions

In X++ an error occurs when you call an instance method on an object variable that has not yet had anything assigned to it. However, no exception is raised along with this error. Therefore no catch block can gain control even if the unassigned variable is misused in a try block. In the following code example, the error caused by the code box4.toString(); does not cause control to transfer to any catch block:

In C# a

System.NullReferenceException is
raised when an uninitialized variable is treated as an object reference.

DialogBox box4; ;

try { box4.toString(); info("toString did not error, but expected an error."); } catch (Exception::Error) // No Exception value catches this. { info("Invalid use of box4 gave control to catch, unexpected."); }
SQL transactions In X++ when an SQL exception occurs in a ttsBegin - ttsCommit transaction, no catch statement inside the transaction block can process the exception. In C# a catch block inside an SQL transaction can catch the exception. For more information about X++ exceptions during SQL transactions, see the following topics:

Deadlocks X++ Standards: ttsBegin and ttsCommit

Exception Handling

X++ and C# Samples This section contains two code samples. One sample is written in X++, and the other is in C#. Both samples achieve the same result. The following X++ features are demonstrated:

try keyword. catch keyword. The behavior after an Exception::Error exception occurs.

X++ Sample Copy Code

static void JobRs008a_Exceptions(Args _args) { str sStrings[4]; int iIndex = 77; ; try { info("On purpose, this uses an invalid index for this array: " + sStrings[iIndex]); warning("This message does not appear in the Infolog," + " it is unreached code."); } // Next is a catch for some of the values of // the X++ Exception enumeration. catch (Exception::CodeAccessSecurity) { info("In catch block for -- Exception::CodeAccessSecurity"); } catch (Exception::Error) { info("In catch block for -- Exception::Error"); } catch (Exception::Warning) {

info("In catch block for -- Exception::Warning"); } catch { info("This last 'catch' is of an unspecified exception."); } //finally //{ // //Global::Warning("'finally' is not an X++ keyword, although it is in C#."); //} info("End of program."); }
Output Here is the actual output from the Infolog window:

Message (18:07:24) Error executing code: Array index 77 is out of bounds. Stack trace (C)\Jobs\JobRs008a_Exceptions - line 8 In catch block for -- Exception::Error End of program.
C# Sample The following C# program is a rewrite of the previous X++ program. Copy Code

using System; public class Pgm_CSharp { static void Main( string[] args ) { new Pgm_CSharp().Rs008a_CSharp_Exceptions(); } void Rs008a_CSharp_Exceptions() { //str sStrings[4]; string[] sStrings = new string[4]; try { Console.WriteLine ("On purpose, this uses an invalid index" + " for this array: " + sStrings[77]); Console.Error.WriteLine ("This message does not appear in the Infolog," + " it is unreached code."); } catch (NullReferenceException exc) { Console.WriteLine("(e1) In catch block for -- " + exc.GetType().ToString() ); } catch (IndexOutOfRangeException exc) { Console.WriteLine("(e2) In catch block for -- " + exc.GetType().ToString() ); } // In C#, System.Exception is the base of all

// .NET Framework exception classes. // No as yet uncaught exception can get beyond // this next catch. catch (Exception exc) { Console.WriteLine ("This last 'catch' is of the abstract" + " base type Exception: " + exc.GetType().ToString()); } // The preceding catch of System.Exception makes this catch of // an unspecified exception redundant and unnecessary. //catch //{ // Console.WriteLine("This last 'catch' is" // + " of an unspecified exception."); //} finally { Console.WriteLine ("'finally' is not an X++ keyword," + " although it is in C#."); } Console.WriteLine("End of program."); } } // EOClass
Output Here is the actual output to the C# console:

(e2) In catch block for -- System.IndexOutOfRangeException 'finally' is not an X++ keyword, although it is in C#. End of program.

Microsoft Dynamics AX 2009

X++, C# Comparison: Automated Retry After an Exception


Sometimes you can write code in a catch block that fixes the cause of an exception that occurs during run time. X++ provides a retry keyword that can be used only inside a catch block. The retry keyword enables a program to jump back to the start of the try block after the problem has been corrected by code in the catch block. C# does not have a retry keyword. However, C# code can be written to provide equivalent behavior. X++ and C# Code Samples for Retry The following X++ sample program causes an Exception::Error to be raised. This occurs when it first tries to read an element from the sStrings array by using an invalid index value. When the exception is caught, corrective action is taken during run time inside the catch block. The retry statement then jumps back to the first statement in the try block. This second iteration works without encountering any exception. Copy Code

static void JobRs008b_ExceptionsAndRetry(Args _args) { str sStrings[4]; str sTemp; int iIndex = 0; ; sStrings[1] = "First array element."; try { print("At top of try block: " + int2str(iIndex)); sTemp = sStrings[iIndex]; print( "The array element is: " + sTemp ); } catch (Exception::Error) { print("In catch of -- Exception::Error (will retry)." + " Entering catch."); ++iIndex; print("In catch of -- Exception::Error (will retry). + " Leaving catch."); // Here is the retry statement. retry; } print("End of X++ retry program."); pause; }
Output Here is the actual output to the Print window:

At top of try block: 0 In catch of -- Exception::Error (will retry). Entering catch. In catch of -- Exception::Error (will retry). Leaving catch. At top of try block: 1 The array element is: First array element. End of X++ retry program.
C# Sample The following C# sample is not a line-by-line translation from the previous X++ sample. Instead the C# program has a different structure so that it mimics the behavior of the retry keyword that the X++ program relies on. The try and catch blocks are in a called method. The variables that are used in the try block are stored in the caller method. The caller method passes the variables as parameters that are decorated with the ref keyword, so that their values can be corrected inside the catch block of the called method. The called method captures all exceptions, and returns a boolean to communicate back to the caller whether a second call is required. Copy Code

using System; public class Pgm_CSharp { static void Main(string[] args) {

new Pgm_CSharp() .Rs008b_CSharp_ExceptionsAndRetry(); } void Rs008b_CSharp_ExceptionsAndRetry() // Caller { int iIndex = -1 , iNumRetriesAllowed = 3; bool bReturnCode = true; // Means call the callee method. for (int xx=0; xx <= iNumRetriesAllowed; xx++) { if (bReturnCode) { bReturnCode = this .Rs008b_CSharp_ExceptionsAndRetry_Callee (ref iIndex); } else { break; } } Console.WriteLine("End of C# caller method."); } private bool Rs008b_CSharp_ExceptionsAndRetry_Callee (ref int iIndex) { bool bReturnCode = true; // Means call this method again. string[] sStrings = new string[4]; string sTemp; sStrings[0] = "First array element."; try { Console.WriteLine("At top of try block: " + iIndex.ToString()); sTemp = sStrings[iIndex]; Console.WriteLine( "The array element is: " + sTemp ); bReturnCode = false; // Means do not call this method again. } catch (Exception) { Console.WriteLine ("In catch of -- Exception. Entering catch."); ++iIndex; // The 'ref' parameter in C#. Console.WriteLine ("In catch of -- Exception. Leaving catch."); //retry; // In C# we let the caller method do the work // that the retry keyword does in X++. } Console.WriteLine("End of C# callee method."); return bReturnCode; } }
Output Here is the actual output to the console:

At top of try block: -1 In catch of -- Exception. Entering catch. In catch of -- Exception. Leaving catch. End of C# callee method. At top of try block: 0 The array element is: First array element.

End of C# callee method. End of C# caller method.

Microsoft Dynamics AX 2009

X++, C# Comparison: Operators


This topic compares the operators between Microsoft Dynamics AX X++ and C#. Assignment Operators The following table displays the differences between the assignment operators in X++ and C#. X++ and C# Differences In X++ this operator causes an implicit conversion whenever a loss of precision might occur, such for an assignment from an int64 to an int. But in C# the assignment causes a compile error. The only difference is that in C# these operators are also used in delegate manipulation.

+=
and

-= ++
and These are the increment and decrement operators in both languages. The following line is identical in both languages:

--

++myInteger;

But in X++ these two operators are for statements, not for expressions. Therefore the following lines generate compile errors in X++:

myStr = int2str(++myInteger); myIntA = myIntBB++;

Arithmetic Operators The following table lists the arithmetic operators. X++ and C# Differences As the multiplication operator, there are no differences. Note The asterisk is also used in the SQL statements that are part of the X++ language. In these SQL statements the asterisk can also be one of the following: A wildcard indicating that all the columns should be returned.

A wildcard for characters in a string that is used on a like clause.

For more information, see Relational Operators.

/ MOD +

The division operator is the same in X++ and C#. For modulo operations, the only difference is that the % symbol is used in C#. The addition operator is the same in X++ and C#. The plus sign is also used for string concatenation. This operator adds numbers and concatenates strings in both languages.

The subtraction operator is the same in X++ and C#.

Bitwise Operators The following table compares the bitwise operators between X++ and C#. X++ and C# Differences The left shift operator is the same in X++ and C#. The right shift operator is the same in X++ and C#. The bitwise NOT operator is the same in X++ and C#. The binary AND operator is the same in X++ and C#. The binary XOR operator is the same in X++ and C#.

<< >> ~ & ^

The binary OR operator is the same in X++ and C#.

Relational Operators The following relational operators are the same in X++ and C#:

== >= <= > < != && || ! ? :

Microsoft Dynamics AX 2009

X++, C# Comparison: Precompiler Directives


X++ and C# share some keywords for their precompiler directive syntax, but the meanings are not always the same. X++ to C# Comparisons The following sections describe the similarities and differences between the precompiler directives used in X++ and C#. Similarities The X++ and C# compilers recognize many of the same keywords. In most cases, the keywords mean the same for both language compilers. Differences A fundamental difference between the precompiler directives in X++ versus C# is the #define keyword that both language precompilers recognize. Unlike C#, in X++ the #define directive requires a dot in its syntax. In X++, parentheses can be used to give the defined symbol a value. These differences are shown in the following examples:

In X++: #define.InitialYear(2003) In C#: #define InitialYear

A minor difference is that in C# there can be spaces and tab characters between the # character and the directive keyword, such as # define Testing. Comparison Tables The following tables compare the details of precompiler directives between X++ and C#. Identical Keywords The following table lists precompiler directives that are similar in X++ and C#. Keyword X++ C# In C#, a precompiler variable name can be defined, but no value can be given to that variable. Also, any #define in C# must occur at the top of the file, and cannot occur after any code such as a using statement or a class declaration. In C#, #if can only determine whether a precompiler variable exists. It cannot test for any value because no value can be assigned. Comments The C# compiler can input a command line parameter of /define to define a precompiler variable name without defining the variable in any C# code file. The X++ compiler has no counterpart to /define.

#define

In X++, a precompiler variable name can be defined, and a value can be given to that variable.

#if

In X++, #if can determine whether a precompiler variable exists, and whether the variable has a given value. In X++, #endif marks the end of an #if block. It also ends an #ifnot block.

#endif

In C#, #endif marks the end of an #if block, regardless of whether the block includes a #else.

Different Keywords with the Same Processing Result The following table lists precompiler directives that are named differently in X++ and C#, but that give the same results when processed. X++ C# Comments There is no #else directive in X++, but the #ifnot provides similar functionality. In X++, #ifnot can determine whether a precompiler variable exists, and whether the variable does not have a specific given value. In C#, #if can determine whether a precompiler variable exists when the ! symbol is prefixed to the variable name.

#ifnot

#if #else

//BP Deviation documented #macrolib

#pragma
warning .HPP file in C++

These X++ and C# entries are not equivalent, but there is a partial similarity. Both suppress compiler warning messages. There is a partial similarity between the X++ directive #macrolib versus an .HPP file in C++. Both can contain several #define statements.

Precompiler Directives Exclusive to X++ The following table lists X++ precompiler directives that have no direct counterpart in C#. X++ Comments

#linenumber

The #linenumber directive is for obtaining the line number, so that it can be output to the Infolog. The C# directive #line is different because its purpose is for setting the line number.

#defdec #definc #globaldefine In X++, there is a small difference between #globaldefine versus #define. The difference is that #globaldefine never overwrites a current nonnull value that was assigned to a precompiler variable by #define.
C# has nothing similar to this difference, because in C#, a precompiler variable name cannot be given a value.

#localmacro #macro

In X++, #localmacro enables you to assign a multiline value to a precompiler variable. #macro is a synonym, but #localmacro is recommended. In C#, the #define directive has part of this functionality, but it cannot assign a value to a precompiler variable.

#globalmacro

In X++, #globalmacro is almost the same as the preferred #localmacro.

Microsoft Dynamics AX 2009

X++, C# Comparison: Classes


When you use C# in the .NET Framework, classes are grouped into namespaces. Each namespace focuses on a functional area such as file operations or reflection. However, when you use the classes in Microsoft Dynamics AX X++, there are no visible groupings like a namespace.

Microsoft Dynamics AX 2009

X++, C# Comparison: Classes about Reflection


In X++ the TreeNode class provides access to the Application Object Tree (AOT). The TreeNode class is the center of reflection functionality in X++. The TreeNode class and its methods can be compared to the System.Reflection namespace in the .NET Framework that C# uses. Table of Class Comparisons The following table lists several classes that are available to you when you write C# code. These are .NET Framework classes. For this table, all C# classes are in the System.Reflection namespace unless otherwise specified. Each row shows the corresponding Microsoft Dynamics AX class, or class member, that is available to you when your write X++ code. X++ C# Comments Assembly is the first class to use when a C# program must gather reflection information. Static methods on the X++ class TreeNode are the starting point for reflection in X++. Instance methods on TreeNode correspond to instance methods on System.Type. The AOTgetSource method returns several pieces of information together in one string. This includes the X++ source code in the method. In contrast, MethodInfo has a separate member for each piece of information.

TreeNode

System .Assembly

TreeNode

System .Type

TreeNode .AOTgetSource

MethodInfo

TreeNode .AOTfirstChild TreeNode .AOTnextSibling TreeNode .AOTiterator AOTiterator

MethodInfo[] (an
array)

In C#, the GetMethods method on System.Type returns an array of MethodInfo objects. You can loop through the array by the common technique of incrementing an indexer. In contrast, the X++ model is to navigate the tree control of the AOT. The TreeNode methods of AOTfirstChild and AOTnextSibling accomplish the navigation. As an equivalent alternative, the X++ AOTiterator class is designed to navigate the tree control of the AOT. A class node is the parent over several method nodes. The AOTiterator steps through child nodes, returning each as another TreeNode instance. See also the TreeNode methods that are named AOTparent and AOTprevious.

TreeNode .AOTgetProperty TreeNode .AOTgetProperties TreeNode .AOTname TreeNode .AOTsave TreeNode .AOTinsert

PropertyInfo

In X++, the AOTgetProperties method returns a long string that contains name-value pairs for all the properties of the TreeNode. The AOTname method returns a string that contains only the value for the name property.

System .Reflection .Emit (namespace of


classes)

The AOTsave method applies changes from a TreeNode object in your X++ code to the AOT, and the changes are persisted. For a large code sample, see TreeNode.AOTsave Method.

Microsoft Dynamics AX 2009

X++, C# Comparison: Classes about File IO


Microsoft Dynamics AX provides several classes that perform file input and output (IO) operations. In the .NET Framework that is used in C#, the counterparts to these classes reside in the System.IO namespace. Table of Class Comparisons

The following table lists several .NET Framework classes for C# that are in the System.IO namespace. Each row in the table shows the X++ class or method that best corresponds to the .NET Framework class. X++ C# Comments X++ classes such as BinaryIo that extend from the abstract class Io serve as a stream, and they also serve as a reader and writer for that stream. In C# the stream is a separate class the from the class that has the more specific read and write methods.

BinaryIo

FileStream BinaryReader BinaryWriter

TextBuffer

MemoryStream

These classes contain an in-memory buffer, and some of the methods treat the buffer as if it were a file on the hard disk. X++ can use static methods in the WINAPI class for many basic operating system functions that involve directories. These classes and methods are used to obtain drive related information. X++ can use static methods in the WINAPI class for many basic operating system functions that involve files.

WINAPI::createDirectory Directory WINAPI::folderExists DirectoryInfo

WINAPI::removeDirectory Path WINAPI::getDriveType DriveInfo DriveType WINAPI::copyFile WINAPI::createFile WINAPI::deleteFile WINAPI::fileExists CommaIo Comma7Io
(No corresponding class.)

File FileAttributes FileInfo

These X++ classes can generate files that Microsoft Excel can import. In X++ the SysExcel Class provides additional interaction with Excel. These classes use different code pages.

AsciiIo TextIo

FileStream TextReader TextWriter

Io

Stream StreamReader StreamWriter FileStream

These are often used as base classes that other classes extend.

CodeAccessPermission FileIoPermission

System.Security .CodeAccessPermission
The namespace System.Security.Permissions includes the following classes:

The concepts and methods of assert, demand, and revertAssert apply to both languages. However, the deny and revertDeny methods that are available in C# are not available in X++.

CodeAccessSecurityAttribute FileIOPermissionAttribute FileIOPermission FileIOPermissionAccess

Microsoft Dynamics AX 2009

X++, ANSI SQL Comparison: SQL Select


In X++, the SQL select statement syntax differs from the American National Standards Institute (ANSI) specification. Single Table Select The following table lists differences between the select statements of X++ SQL and ANSI SQL. Feature Table name on the from clause. X++ SQL The from clause lists a record buffer instance that is declared from a table, such as from the CustTable table. ANSI SQL The from clause lists a table name, not the name of a buffer. Comments The record buffer has all the methods that the xRecordclass has in X++. In both X++ and ANSI SQL, the from and join clauses must appear before the order by and where clauses.

Syntax sequence of the order by versus where clauses.

The order by clause must appear before the where clause. The order by clause must appear after the from or join clause. The group by clause must follow the same syntax positioning rules that the order by follows. The exclamation mark ('!') is used for negation.

The order by clause must appear after the where clause. The where clause must appear after the from or join clause.

Condition negation.

The not keyword is used for negation.

X++ does not support the syntax !like. Instead, you must apply the ! operator to a clause. For more information, see Relational Operators.

Wildcard characters for the like operator.

0 to many Asterisk ('*') Exactly 1 Question mark ('?')

0 to many Percent sign ('%') Exactly 1 Underbar ('_')

Logical operators in the where clause.

And && Or ||

And and Or or

For more information, see Relational Operators.

Code Example The following code example illustrates features in the previous table. Copy Code

static void OByWhere452Job(Args _args) { // Declare the table buffer variable. CustTable tCustTable; ; while SELECT * from tCustTable order by tCustTable.AccountNum desc where (!(tCustTable.Name like '*i*i*') && tCustTable.Name like 'T?e *') { info(tCustTable.AccountNum + " , " + tCustTable.Name); } } /*** InfoLog output Message (04:02:29 pm) 4010 , The Lamp Shop 4008 , The Warehouse 4001 , The Bulb ***/
Join Clause The following table lists differences about the join keyword of X++ SQL and ANSI SQL. Feature Columns list. X++ SQL The columns in the columns list must all come from the table listed in the from clause, and not from any table in a join ANSI SQL Comments

The columns in the columns list can For more information, come from any table in the from or join see Select Statements on clauses. It helps others to maintain your

clause. Columns in the list cannot be qualified by their table name. Join clause syntax. The join clause follows the where clause.

code when you qualify the columns in the list with their table name. The join clause follows a table in the from clause.

Fields.

In the X++ code example, the join criteria is an equality of SalesPoolId values. The outer keyword exists in both X++ SQL and ANSI SQL. No comments.

Inner keyword.

The default join mode is inner join. There is no inner keyword.

The default join mode is inner join. The inner keyword is available to make the code explicit. The left and right keywords are available to modify the join keyword.

Left and right keywords. Equality operator.

The left and right keywords are not available. All joins are left.

The double equal sign operator ('==') is used to test for the equality of two values.

The single equal sign operator ('=') is used to test for the equality of two values.

No comments.

Code Example The following code example illustrates the join syntax in X++ SQL. Copy Code

static void OByWhere453Job(Args _args) { // Declare table buffer variables. CustTable tCustTable; SalesPool tSalesPool; ; while SELECT // Not allowed to qualify by table buffer. // These fields must be from the table // in the from clause. AccountNum, Name from tCustTable order by tCustTable.AccountNum desc where (tCustTable.Name like 'The *') join tSalesPool where tCustTable.SalesPoolId == tSalesPool.SalesPoolId { info(tCustTable.AccountNum + " , " + tCustTable.Name); } }
Aggregate Fields The following table lists some differences in how aggregate fields in the select column list are referenced between X++ SQL and ANSI SQL. Aggregate fields are those that are derived by functions such as sum or avg. Feature Aggregate field name alias. X++ SQL The aggregate value is in the field that was aggregated. ANSI SQL You can use the as keyword to tag an aggregate field with a name alias. The alias can be referenced in subsequent code. Comments For more information, see Aggregate Functions: Differences Between X++ and SQL

Code Example In the following code example, the call to the info method illustrates the way to reference aggregate fields (see tPurchLine.QtyOrdered).

Copy Code

static void Null673Job(Args _args) { PurchLine tPurchLine; ; while select // This aggregate field cannot be assigned an alias name. sum(QtyOrdered)

from tPurchLine { info( // QtyOrdered is used to reference the sum. "QtyOrdered: " + num2str(tPurchLine.QtyOrdered, 3, // Minimum number of output characters. 2, // Required number of decimal places in the output. 1, // '.' Separator to mark the start of the decimal places. 2 // ',' The thousands separator. )); } info("End."); } /*** Message (12:23:08 pm) QtyOrdered: 261,550.00 End. ***/
Other Differences The following table lists other differences of the select statement between the X++ SQL and ANSI SQL. Feature The having keyword. X++ SQL There is no having keyword. ANSI SQL The having keyword enables you to specify filter criteria for rows that are generated by the group by clause. Comments No comments.

Null results.

In a while select statement, if the where clause filters out all rows, no special count row is returned to report that.

In a select, if the where No comments. clause filters out all rows, a special count row is returned. The count value is 0. You can declare a cursor for looping through the rows that are returned from a select statement. A select statement cannot read from a table unless the from clause is used. For more information, see Methods in X++.

Cursors for navigating returned rows. From clause.

The while select statement provides cursor functionality. The alternative is to use the next keyword. The from keyword is optional when no columns are listed and only one table is referenced. The following two syntax options are equivalent:

In X++ SQL, the simple select statement fills the table buffer variable with the first row that was returned. This is illustrated by the following code fragment:

select * from tCustTable; info(tCustTable.Name);

select * from tCustTable; select tCustTable;

Vous aimerez peut-être aussi