x++, c# comparison

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 X++ C# Comments Declarations All declarations must be at the start of the method, before any X++ statements. Declarations can occur anywhere in the method. 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. Extra semicolon (;) An extra semicolon (;) is needed after the last declaration, and before any statements, in each method. Not needed in C#. The X++ compiler requires the extra semicolon. For more information, see X++ Standards: Using Semicolons if and elseconditional statements 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. The if statement requires a Boolean expression. The syntax structure regarding curly braces and parentheses is exactly the same between X++ and C#. Literal string A literal string can be delimited by either of the following: A pair of double quotation mark (") characters. A pair of single quotation mark (') characters. A literal string must be delimited by a pair of double 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. 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 more information about X++ data types, see Primitive Data Types. Output of messages X++ delivers messages to the user in the Infolog window. Common methods include the following: The print statement: static methods on the Global class: Global::info Global::warning Global::error For a command line C# program, messages can be delivered to the console. Common methods include the following: Console.Out.WriteLine Console.Error.WriteLine 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

Upload: kashyap-patel

Post on 10-Mar-2015

1.337 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: X++, C# Comparison

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 X++ C# Comments

Declarations All declarations must be at the start of the method, before any X++ statements.

Declarations can occur anywhere in the method.

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.

Extra semicolon (;)

An extra semicolon (;) is needed after the last declaration, and before any statements, in each method.

Not needed in C#. The X++ compiler requires the extra semicolon. For more information, see X++ Standards: Using Semicolons

if and

elseconditional

statements

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.

The if statement requires a

Boolean expression.

The syntax structure regarding curly braces and parentheses is exactly the same between X++ and C#.

Literal string A literal string can be delimited by either of the following:

A pair of double quotation

mark (") characters.

A pair of single quotation

mark (') characters.

A literal string must be delimited by a pair of double 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.

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 more information about X++ data types, see Primitive Data Types.

Output of messages

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

The print statement:

static methods on the

Global class:

Global::info

Global::warning

Global::error

For a command line C# program, messages can be delivered to the console. Common methods include the following:

Console.Out.WriteLine

Console.Error.WriteLine

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

Page 2: X++, C# Comparison

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:

Page 3: X++, C# Comparison

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.

Page 4: X++, C# Comparison

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 X++ C# Discussion

The for

statement.

The for statement is available for loops.

The C# for statement is slightly

different from for in X++.

In C# you can declare the counter

integer in the for statement. But

in X++ the counter must declared

outside the for statement.

++ 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: int age=42; print age++;

However, the following lines of X++ code would compile: int age=42; age++; print

age;

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

The following lines of code are the same in both languages:

++ myInteger;

myInteger++;

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

yourInt = ++myInt;

yourInt = myInt++;

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.

Temporarily suspend a console program that has already begun.

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

Console.In.Read();

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.

Display a message.

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

In C# a message can be displayed on the console by the following line of code:

Console.WriteLine();

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.

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();

The statements each produce a

short tone.

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.

Page 5: X++, C# Comparison

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:

Page 6: X++, C# Comparison

[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());

Page 7: X++, C# Comparison

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.)

Page 8: X++, C# Comparison

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++ C# Comments

==

comparison operator

Insensitive: the == operator is

insensitive to differences in string casing.

In C#, the == operator is

sensitive to differences in string casing.

In X++ you can use the strCmp Function for case sensitive comparisons between strings.

String delimiters

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.

In C# you must use the double quotation mark as the string delimiter. This refers to the type

System.String.

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.

Character delimiters

X++ has a string data type (str), but

no character type.

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

"HELLO" == "hello"

True in X++.

"HELLO" == "hello"

False in C#. Different case comparisons between X++ and 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# Comments

myString1 = "Hello" +

" world";

Result is equality: myString1 ==

"Hello world"

(Same as for X++.)

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.

mystring2 = "Hello"; myString2 +=

" world";

Result is equality: myString2 ==

"Hello world"

(Same as for X++.)

In both X++ and C#, the following statements are equivalent: a = a + b; a += b;

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# Comments

myString1 = (Same as for X++.) The escape character enables you to embed string

Page 9: X++, C# Comparison

"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.

myString3 =

"He said 'yes'.";

Result: He said 'yes'.

(Same as for X++.) 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.

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.

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.

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# Comments

myString1 =

"Red\ shoe";

Result: Red shoe

A literal string in C# cannot contain the two character sequence of escape followed by a space,

such as "\ ". A compiler error occurs.

When the X++ compiler encounters the two

character sequence of "\ ", it discards the

single escape character.

myString2 =

"Red\\ shoe";

Result: Red\ shoe

(Same as for X++.) In a pair of escape characters, the first negates the special meaning of the second.

Page 10: X++, C# Comparison

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# Comments

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

An array is declared with square brackets appended to the data type.

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.

The array syntax supports primitive data types and classes.

In X++ you can use the Array class for an

array of objects.

Declaration X++ is limited to single dimension

arrays (myStrings[8]).

C# adds support for multi-dimensional 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.

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.

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.

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.

C# arrays are objects that

have a Length property.

No comments.

Indexing Array indexing is 1 based. 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

Page 11: X++, C# Comparison

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();

}

Page 12: X++, C# Comparison

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]

Page 13: X++, C# Comparison

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 X++ C# Discussion

Declaration of collection

List myList; List<string> myList; The X++ declaration does not include the type of elements to be stored.

Declaration of iterator

ListIterator iter;

ListEnumerator enumer;

IEnumerator<string> iter; In X++ the

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.

Constructor new List(Types::String) new List<string>() Information about the type of objects to be

stored inside the List

classes is given to the constructor in both X++ and C#.

Updating data

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.

Enumerator – the enumerator becomes invalid if any items in the

List are added or removed.

Enumerators become invalid after items are added or deleted from

the List, in both X++

and C#.

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;

Page 14: X++, C# Comparison

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.");

listStrings.Add ("String_BB.");

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

// Iterator performs a midpoint

// insert at current position.

listIterator.insert ("dog");

// Index 7 determines the insertion point.

listStrings.Insert (7 ,"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.

while (literator.more())

{

info(any2str

(literator.value()));

literator.next();

}

// The MoveNext method both

// advances the item pointer, and

// answers whether the pointer is

// pointing at an item.

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);

Page 15: X++, C# Comparison

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);

Page 16: X++, C# Comparison

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 X++ C# Comments

Duplicate keys

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 C# the Dictionary class

throws an exception when you try to add a duplicate key.

Duplicate keys are prevented in both languages, although by different techniques.

Delete items

In X++ the delete method on an iterator

object is used to remove an unwanted key-

value pair from a Map.

In C# the Dictionary class

has a remove method.

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#

Page 17: X++, C# Comparison

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();

}

Page 18: X++, C# Comparison

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 X++ C# Comments

retry Jumps to the first instruction in the associated try block. For more information, see Exception Handling.

The functionality of the retry keyword can be mimicked in C# code, but there is no corresponding keyword.

Only X++ has a retry keyword. C# has no counterpart. For more information, see X++, C# Comparison: Automated Retry After an Exception.

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.

Only C# has a finally keyword. X++ has no counterpart.

Specific exceptions

In X++ an exception is an element of the

Exception enum, such as:

Error

Deadlock

CodeAccessSecurity

No exception can contain another.

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.

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

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.

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:

DialogBox box4;

;

In C# a

System.NullReferenceException is

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

There might be several other differences in the conditions that raise exceptions.

Page 19: X++, C# Comparison

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)

{

Page 20: X++, C# Comparison

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

Page 21: X++, C# Comparison

// .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.

Page 22: X++, C# Comparison

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)

{

Page 23: X++, C# Comparison

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.

Page 24: X++, C# Comparison

End of C# callee method.

End of C# caller method.

Page 25: X++, C# Comparison

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.

+=

and

-=

The only difference is that in C# these operators are also used in delegate manipulation.

++

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.

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

MOD 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#.

Page 26: X++, C# Comparison

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

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

==

>=

<=

>

<

!=

&&

||

!

? :

Page 27: X++, C# Comparison

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# Comments

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

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.

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.

#if In X++, #if can

determine whether a precompiler variable exists, and whether the variable has a given value.

In C#, #if can only determine whether a

precompiler variable exists. It cannot test for any value because no value can be assigned.

#endif In X++, #endif marks

the end of an #if block.

It also ends an #ifnot

block.

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

#ifnot #if

#else

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.

//BP Deviation

documented #pragma

warning These X++ and C# entries are not equivalent, but there is a partial similarity. Both suppress compiler warning messages.

#macrolib .HPP file in C++

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

Page 28: X++, C# Comparison

#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.

Page 29: X++, C# Comparison

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

TreeNode System .Assembly 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++.

TreeNode System .Type Instance methods on TreeNode correspond to instance methods on

System.Type.

TreeNode

.AOTgetSource MethodInfo 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

.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

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.

TreeNode .AOTsave

TreeNode .AOTinsert

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

Page 30: X++, C# Comparison

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

BinaryIo FileStream

BinaryReader

BinaryWriter

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.

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.

WINAPI::createDirectory

WINAPI::folderExists

WINAPI::removeDirectory

Directory

DirectoryInfo

Path

X++ can use static methods in the

WINAPI class for many basic operating

system functions that involve directories.

WINAPI::getDriveType DriveInfo

DriveType

These classes and methods are used to obtain drive related information.

WINAPI::copyFile

WINAPI::createFile

WINAPI::deleteFile

WINAPI::fileExists

File

FileAttributes

FileInfo

X++ can use static methods in the

WINAPI class for many basic operating

system functions that involve files.

CommaIo

Comma7Io

(No corresponding class.) These X++ classes can generate files that Microsoft Excel can import. In X++ the SysExcel Class provides additional interaction with Excel.

AsciiIo

TextIo

FileStream

TextReader

TextWriter

These classes use different code pages.

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:

CodeAccessSecurityAttribute

FileIOPermissionAttribute

FileIOPermission

FileIOPermissionAccess

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++.

Page 31: X++, C# Comparison

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 X++ SQL ANSI SQL Comments

Table name on the from clause.

The from clause lists a record buffer instance that is declared from a table, such as from

the CustTable table.

The from clause lists a table name, not the name of a buffer.

The record buffer has all the methods that the

xRecordclass has in

X++.

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 order by clause must appear after the where clause. The where clause must appear after the from or join clause.

In both X++ and ANSI SQL, the from and join clauses must appear before the order by and where clauses.

Condition negation.

The exclamation mark ('!') is used for

negation.

The not keyword is used for negation.

X++ does not support

the syntax !like.

Instead, you must apply

the ! operator to a

clause.

Wildcard characters for the like operator.

0 to many – Asterisk ('*')

Exactly 1 – Question mark ('?')

0 to many – Percent

sign ('%')

Exactly 1 – Underbar

('_')

For more information, see Relational Operators.

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 X++ SQL ANSI SQL Comments

Columns list.

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

The columns in the columns list can come from any table in the from or join clauses. It helps others to maintain your

For more information, see Select Statements on

Page 32: X++, C# Comparison

clause. Columns in the list cannot be qualified by their table name.

code when you qualify the columns in the list with their table name.

Fields.

Join clause syntax.

The join clause follows the where clause.

The join clause follows a table in the from clause.

In the X++ code example, the join criteria is an equality of

SalesPoolId values.

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 outer keyword exists in both X++ SQL and ANSI SQL.

Left and right keywords.

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

The left and right keywords are available to modify the join keyword.

No comments.

Equality operator.

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 X++ SQL ANSI SQL Comments

Aggregate field name alias.

The aggregate value is in the field that was aggregated.

You can use the as keyword to tag an aggregate field with a name alias. The alias can be referenced in subsequent code.

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)

Page 33: X++, C# Comparison

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 X++ SQL ANSI SQL Comments

The having keyword.

There is no having keyword. The having keyword enables you to specify filter criteria for rows

that are generated by the group by clause.

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 clause filters out all rows, a special count row is returned. The count value is 0.

No comments.

Cursors for navigating returned rows.

The while select statement provides cursor functionality. The alternative is to use the next keyword.

You can declare a cursor for looping through the rows that are returned from a select statement.

For more information, see Methods in X++.

From clause. The from keyword is optional when no columns are listed and only one table is referenced. The following two syntax options are equivalent:

select * from tCustTable;

select tCustTable;

A select statement cannot read from a table unless the from clause is used.

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);