Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Hinweis
Community-Interessensgruppen sind jetzt von Yammer zu Microsoft Viva Engage gewechselt. Um an einer Viva Engage-Community teilzunehmen und an den neuesten Diskussionen teilzunehmen, füllen Sie das Formular "Anfordern des Zugriffs auf Finance and Operations Viva Engage Community" aus , und wählen Sie die Community aus, der Sie beitreten möchten.
In diesem Artikel werden die X++- und C#-Syntax und die Programmierung verglichen.
X++-, C#-Vergleich: Hello World
In diesem Abschnitt wird das einfachste X++-Programm mit seinem Gegenstück in C# verglichen.
X++-zu-C#-Vergleiche
In den folgenden Abschnitten werden einige grundlegende Ähnlichkeiten und Unterschiede zwischen X++ und C# beschrieben.
Ähnlichkeiten
Die folgenden X++-Features sind für C# identisch:
- Einzeilige (
//) und mehrzeilige (/* */) Kommentare. -
==(gleich) Operator zum Bestimmen, ob zwei Werte gleich sind. -
!=(nicht gleich) Operator zum Bestimmen, ob zwei Werte nicht gleichwertig sind. -
+(Pluszeichen)-Operator für Zeichenfolgenverkettung.
Unterschiede
In der folgenden Tabelle sind X++-Features aufgeführt, die in C# unterschiedlich sind.
| Merkmal | X++ | C# | Kommentare |
|---|---|---|---|
if und else bedingte Anweisungen |
Die if Anweisung akzeptiert einen beliebigen Ausdruckstyp, der automatisch in einen booleschen Ausdruck konvertiert werden kann. Häufige Beispiele sind eine int 0, für die "false" oder ein Objekt, für das Null "false" bedeutet. |
Für die if Anweisung ist ein boolescher Ausdruck erforderlich. |
Die Syntaxstruktur für geschweifte Klammern und Klammern ist identisch zwischen X++ und C#. |
| Literale Zeichenfolge | Eine Literalzeichenfolge kann mit einer der folgenden Methoden getrennt werden:
|
Eine Literalzeichenfolge muss durch ein Paar doppelter Anführungszeichen (") getrennt werden. | Bei X++ werden die doppelten Anführungszeichen in der Regel verwendet, um Zeichenfolgen zu trennen. Es ist jedoch praktisch, eine Zeichenfolge mit einfachen Anführungszeichenzeichen zu trennen, wenn ihre Zeichenfolge ein doppeltes Anführungszeichenzeichen enthalten muss. |
verkohlen type |
In X++ ist kein char Zeichentyp oder kein Zeichentyp vorhanden. Sie können eine str länge 1 deklarieren, aber es ist immer noch eine Zeichenfolge:str 1 myString = "a"; |
Es gibt eine char In C#-Datei. Sie können einen char Parameter nicht als Parameter an eine Methode übergeben, die einen string Parameter eingibt, obwohl Sie den char Parameter zuerst explizit in ein string. |
Weitere Informationen zu X++-Datentypen finden Sie unter primitive Datentypen. |
| Ausgabe von Nachrichten | X++ übermittelt nachrichten an den Benutzer im Infolog-Fenster. Zu den gängigen Methoden gehören:
|
Für ein Befehlszeilenprogramm können Nachrichten an die Konsole übermittelt werden. Zu den gängigen Methoden gehören:
|
X++- und C#-Beispiele
Dieser Abschnitt enthält zwei einfache Codebeispiele. Ein Beispiel wird in X++ geschrieben, und das andere ist in C#. Beide Proben erzielen dasselbe Ergebnis. Die folgenden X++-Features werden veranschaulicht:
-
//Einzelzeilenkommentar -
/\*\*/Mehrzeilige Kommentare -
if-Anweisung -
==-Operator -
!=-Operator -
+Operator zum Verketten von Zeichenfolgen - Global::info für die Nachrichtenausgabe mit und ohne das Präfix Global::
- Global::error für die Nachrichtenausgabe
- Die Verwendung von einfachen und doppelten Anführungszeichen (' und ") als Zeichenfolgentrennzeichen.
Hinweis
Die bewährte Methode besteht darin, doppelte Anführungszeichen für eine beliebige Zeichenfolge zu verwenden, die dem Benutzer angezeigt werden kann.
X++-Beispiel
Dieses X++-Codebeispiel befindet sich in Form eines Auftrags. Es gibt einen Knoten mit dem Titel "Aufträge" in der Application-Objektstruktur (Application Object Tree, AOT). Dieses Beispiel kann unter dem Knoten Aufträge hinzugefügt werden, und dann kann der Auftrag ausgeführt werden.
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
Hier sehen Sie die Ausgabe aus dem Infolog-Fenster: Nachricht (09:49:48) Hello World, 1. Hallo Welt, 2. Dies ist wie Informationen, aber für Warnungen, 3. Dies ist wie Informationen, aber für Fehler, 4.
C#-Beispiel
Das folgende C#-Programm ist eine Neuschreibung des vorherigen X++-Programms.
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
Hier sehen Sie die tatsächliche Ausgabe in der C#-Konsole:
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.
X++-, C#-Vergleich: Schleifen
In diesem Abschnitt werden die Schleifenfeatures zwischen X++ und C# verglichen.
Ähnlichkeiten
Die folgenden Features sind in X++ und C# identisch:
- Deklarationen für Variablen des Int-Grundtyps. Deklarationen für andere Grundtypen sind fast identisch, aber die Typen haben möglicherweise unterschiedliche Namen.
- while-Anweisung für Schleifen.
- break-Anweisung zum Beenden einer Schleife.
- continue-Anweisung, um zum Anfang einer Schleife zu springen.
- <= (kleiner oder gleich) Vergleichsoperator.
Unterschiede
In der folgenden Tabelle sind X++-Features aufgeführt, die in C# unterschiedlich sind.
| Features | X++ | C# | Kommentare |
|---|---|---|---|
Die for Anweisung. |
Die for-Anweisung ist für Schleifen verfügbar. | Die C# for -Anweisung unterscheidet sich geringfügig von for X++. |
In C# können Sie die Zählerzahl in der for Anweisung deklarieren. In X++ muss der Zähler jedoch außerhalb der for Anweisung deklariert werden. |
| ++ inkrementierungsoperator. | Ein ++-Inkrementoperator ist in X++ verfügbar. Eine int-Variable , die mit ++ versehen ist, kann jedoch nur als Anweisung und nicht als Ausdruck verwendet werden. Die folgenden X++-Codezeilen würden z. B. nicht kompiliert:int age=42;print age++;Die folgenden X++-Codezeilen würden jedoch kompiliert: int age=42;age++; print age; |
Der C#++-Operator ist flexibler als in X++. | Die folgenden Codezeilen sind in beiden Sprachen identisch:
|
| modulo-Operator. | In X++ ist der Modulooperator mod. | In C# ist der Modulooperator %. | Die Symbole für den Modulooperator unterscheiden sich, aber ihr Verhalten ist in beiden Sprachen identisch. |
| Vorübergehendes Anhalten eines Konsolenprogramms, das bereits begonnen hat. | Die pause Anweisung. |
In C# kann ein Befehlszeilenprogramm mit der folgenden Codezeile angehalten werden:Console.In.Read(); |
In X++ fahren Sie fort, indem Sie auf eine OK-Schaltfläche in einem modalen Dialogfeld klicken. In C# fahren Sie fort, indem Sie eine beliebige Tastatur auf der Tastatur drücken. |
| Zeigt eine Meldung an. | In X++ zeigt die print Anweisung eine Meldung im Fenster "Drucken" an. |
In C# kann eine Meldung über die folgende Codezeile auf der Konsole angezeigt werden:Console.WriteLine(); |
Die X++- print Funktion wird nur beim Testen verwendet. Ein X++-Programm, das print fast immer die pause Anweisung weiter unten im Code verwendet. Verwenden Sie für X++-Produktionscode die Global::info-Methode anstelle von print. Die strfmt Funktion wird häufig zusammen mit info. Es gibt keinen Grund, danach pausezu verwendeninfo. |
| Machen Sie einen Sound. | Die Signaltonfunktion macht einen Sound, den Sie hören können. | In C# wird ein Sound ausgegeben, den Sie hören können, indem Sie die folgende Codezeile verwenden:Console.Beep(); |
Die Anweisungen erzeugen jeweils einen kurzen Ton. |
Drucken und Global::info
Die X++-Codebeispiele für Schleifen verwenden die print Funktion zum Anzeigen von Ergebnissen. In X++ können Sie die print Anweisung verwenden, um einen beliebigen primitiven Datentyp anzuzeigen, ohne zuerst Funktionen aufrufen zu müssen, die sie in eine Zeichenfolge konvertieren. Dies macht print in Schnelltestsituationen nützlich. Im Allgemeinen wird die Global::info-Methode häufiger als printverwendet. Die info Methode kann nur Zeichenfolgen anzeigen. Daher wird die Strfmt-Funktion häufig zusammen mit info. Eine Einschränkung print besteht darin, dass Sie den Inhalt des Druckfensters nicht in die Zwischenablage kopieren können (z. B. mit STRG+C). Global::info schreibt in das Infolog-Fenster, das das Kopieren in die Zwischenablage unterstützt.
Beispiel 1: Die While-Schleife
Das Schlüsselwort while unterstützt Schleifen sowohl in X++ als auch in C#.
X++-Beispiel für "While"
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
Die Ausgabe im X++-Druckfenster lautet wie folgt:
1
2
3
4
C#-Beispiel für "While"
using System;
public class Pgm_CSharp
{
static void Main( string[] args )
{
new Pgm_CSharp().WhileLoops();
}
void WhileLoops()
{
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
Die Konsolenausgabe des C#-Programms lautet wie folgt:
1
(Press any key to resume.)
2
(Press any key to resume.)
3
(Press any key to resume.)
4
(Press any key to resume.)
Beispiel 2: For-Schleife
Das Schlüsselwort unterstützt Schleifen sowohl in X++ als auch in C#.
X++-Beispiel für
In X++ kann die Zählervariable nicht als Teil der for-Anweisung deklariert werden.
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;
}
Output
Die Ausgabe im X++-Druckfenster lautet wie folgt:
1
2
3
4
C#-Beispiel für
using System;
public class Pgm_CSharp
{
static void Main( string[] args )
{
new Pgm_CSharp().ForLoops();
}
void ForLoops()
{
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
Die Konsolenausgabe des C#-Programms lautet wie folgt:
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.)
X++-, C#-Vergleich: Switch
Sowohl in X++ als auch in C# umfasst die Switch-Anweisung die Groß -/ Kleinschreibung, den Umbruch und den Standardwert. In der folgenden Tabelle sind die Unterschiede in der Switch-Anweisung zwischen X++ und C# aufgeführt.
| Merkmal | X++ | C# | Kommentare |
|---|---|---|---|
break; am Ende jedes Fallblocks |
In X++ werden alle anderen Groß- und Kleinschreibungen so lange ausgeführt, bis eine Anweisung erreicht ist, wenn ein Block mit dem Ausdruckswert der break; übereinstimmt. In einer X++break; ist nie eine Anweisung erforderlich, aber break; Anweisungen sind in fast allen praktischen Situationen wichtig. |
In C# wird eine break; Anweisung immer nach den Anweisungen in einem Fall oder Standardblock benötigt. Wenn eine Case-Klausel keine Anweisungen zwischen sich selbst und der nächsten Fallklausel enthält, ist eine break; Anweisung zwischen den beiden Case-Klauseln nicht erforderlich. |
Es wird empfohlen, die break; Anweisung nach jedem Fallblock auszulassen, da sie den nächsten Programmierer verwirren kann, der den Code bearbeitet. |
break;am Ende des Standardblocks |
In X++ gibt es keinen Effekt, eine break; Anweisung am Ende des Standardblocks hinzuzufügen. |
In C# erfordert der Compiler eine break; Anweisung am Ende des Standardblocks . |
Weitere Informationen finden Sie unter Switch-Anweisungen. |
| Nur Konstantenwerte für einen Fallblock | In X++ können Sie entweder einen Literalwert oder eine Variable für einen Fallblock angeben. Sie können beispielsweise "myInteger:" schreiben. | In C# müssen Sie genau einen Literalwert für jeden Fallblock angeben, und es sind keine Variablen zulässig. | Keine Kommentare. |
| Mehrere Werte in einem Fallblock | In X++ können Sie für jeden Fallblock mehrere Werte angeben. Die Werte müssen durch ein Komma getrennt werden. Sie können z. B. schreiben case 4,5,myInteger:. |
In C# müssen Sie genau einen Wert für jeden Fallblock angeben. | In X++ ist es besser, mehrere Werte in einem Fallblock zu schreiben, als die break; Anweisung am Ende einer oder mehrerer Fallblöcke auszulassen. |
Codebeispiele für Switch
In den folgenden Abschnitten werden vergleichbare Switch-Anweisungen in X++ und C# gezeigt.
X++-Switch (Beispiel)
Das X++-Switchbeispiel zeigt Folgendes:
-
case iTemp:undcase (93-90):um zu zeigen, dass Fallausdrücke nicht auf Konstanten beschränkt sind, wie sie sich in C# befinden. -
//break;um zu zeigen, dassbreak;Anweisungen in X++ nicht erforderlich sind, obwohl sie fast immer wünschenswert sind. -
case 2, (93-90), 5:um anzuzeigen, dass mehrere Ausdrücke in einer Fallklausel in X++ aufgeführt werden können.
static void GXppSwitchJob21(Args _args) // X++ job in AOT > Jobs.
{
int iEnum = 3;
int iTemp = 6;
switch (iEnum)
{
case 1:
case iTemp: // 6
info(strFmt("iEnum is one of these values: 1,6: %1", iEnum));
break;
case 2, (93-90), str2Int("5"): // Equivalent to three 'case' clauses stacked, valid in X++.
//case 2:
//case (93-90): // Value after each 'case' can be a constant, variable, or expression; in X++.
//case str2Int("5"):
info(strFmt("iEnum is one of these values: 2,3,5: %1", iEnum));
//break; // Not required in X++, but usually wanted.
case 4:
info(strFmt("iEnum is one of these values: 4: %1", iEnum));
break;
default:
info(strFmt("iEnum is an unforeseen value: %1", iEnum));
break;
// None of these 'break' occurrences in this example are required for X++ compiler.
}
return;
}
/*** Copied from the Infolog:
Message (02:32:08 pm)
iEnum is one of these values: 2,3,5: 3
iEnum is one of these values: 4: 3
***
C#-Schalter (Beispiel)
Das C#-Schalterbeispiel zeigt Folgendes:
- Fall 1: Enthält einen Kommentar, der erklärt, dass nur konstanten Ausdrücke in einer Fallklausel angegeben werden können.
-
break;Anweisungen treten nach der letzten Anweisung in jedem Fallblock mit Anweisungen auf, wie von C# erforderlich.
using System;
namespace CSharpSwitch2
{
class Program
{
static void Main(string[] args) // C#
{
int iEnum = 3;
switch (iEnum)
{
case 1: // Value after each 'case' must be a constant.
case 6:
Console.WriteLine("iEnum is one of these values: 1,6: " + iEnum.ToString());
break;
//case 2,3,5: // In C# this syntax is invalid, and multiple 'case' clauses are needed.
case 2:
case 3:
case 5:
Console.WriteLine("iEnum is one of these values: 2,3,5: " + iEnum.ToString());
break;
case 4:
Console.WriteLine("iEnum is one of these values: 4: " + iEnum.ToString());
break;
default:
Console.WriteLine("iEnum is an unforeseen value: " + iEnum.ToString());
break;
// All 'break' occurrences in this example are required for C# compiler.
}
return;
}
}
}
/*** Output copied from the console:
>> CSharpSwitch2.exe
iEnum is one of these values: 2,3,5: 3
>>
***/
X++-, C#-Vergleich: Zeichenfolgenfall und Trennzeichen
In diesem Abschnitt wird die Behandlung von Zeichenfolgen mit gemischter Groß-/Kleinschreibung in X++ und C# verglichen. Außerdem werden die Zeichenfolgentrennzeichen erläutert, die in X++ verfügbar sind.
Ähnlichkeiten
Die folgenden X++-Features sind identisch mit C#:
- Der umgekehrte Schrägstrich (\) ist der Escapeoperator für Zeichenfolgentrennzeichen.
- Mit dem At-Zeichen (@) wird der Escapeeffekt des umgekehrten Schrägstrichs aufgehoben, wenn das At-Zeichen unmittelbar vor dem geöffneten Anführungszeichen einer Zeichenfolge geschrieben wird.
- Das Pluszeichen (+) ist der Zeichenfolgenverkettungsoperator.
Unterschiede
X++-Features, die in C# unterschiedlich sind, sind in der folgenden Tabelle aufgeführt.
| Merkmal | X++ | C# | Kommentare |
|---|---|---|---|
== Vergleichsoperator |
Nicht beachtet: Der == Operator ist nicht auf Unterschiede bei der Zeichenfolgen-Groß-/Kleinschreibung zu reagieren. |
In C# ist der == Operator für Unterschiede bei der Zeichenfolgen-Groß-/Kleinschreibung vertraulich. |
In X++ können Sie die strCmp-Funktion für Vergleiche zwischen Zeichenfolgen verwenden. |
| Zeichenfolgentrennzeichen | In X++ können Sie entweder das einfache (') oder doppelte (") Anführungszeichen als Zeichenfolgentrennzeichen verwenden.Anmerkung: In der Regel empfiehlt es sich, doppelte Anführungszeichen für Zeichenfolgen zu verwenden, die dem Benutzer angezeigt werden können. Es ist jedoch praktisch, eine Zeichenfolge mit einfachen Anführungszeichen zu trennen, wenn ein doppeltes Anführungszeichen eines der Zeichen in der Zeichenfolge ist. |
In C# müssen Sie das doppelte Anführungszeichen als Zeichenfolgentrennzeichen verwenden. Dies bezieht sich auf den Typ System.String. |
In X++ und C# haben Sie die Möglichkeit, ein Trennzeichen in eine Literalzeichenfolge einzubetten und es zu entfernen. In X++ können Sie auch einfache Anführungszeichen in eine Zeichenfolge einbetten, die durch doppelte Anführungszeichen (oder umgekehrt) getrennt ist, ohne das Escapezeichen verwenden zu müssen. |
| Zeichentrennzeichen | X++ hat einen Zeichenfolgendatentyp (str), aber keinen Zeichentyp. |
In C# müssen Sie das einfache Anführungszeichen als Zeichentrennzeichen verwenden. Dies bezieht sich auf den Typ System.Char. |
In .NET Framework ist eine Länge ein System.String anderer Datentyp als ein System.Char Zeichen. |
Beispiel 1: Groß-/Kleinschreibung des == Operators
Bei den == Operatoren und != wird die Groß-/Kleinschreibung in X++ nicht beachtet, die Groß-/Kleinschreibung wird jedoch in C# beachtet, wie im folgenden Beispiel dargestellt.
| X++ | C# | Kommentare |
|---|---|---|
"HELLO" == "hello" True in X++. |
"HELLO" == "hello" False in C#. |
Verschiedene Groß-/Kleinschreibungsvergleiche zwischen X++ und C#. |
Beispiel 2: Der +String-Verkettungsoperator
Die Operatoren +und += werden verwendet, um Zeichenfolgen sowohl in X++ als auch in C# zu verketten, wie in den Beispielen in der folgenden Tabelle dargestellt.
| X++ | C# | Kommentare |
|---|---|---|
myString1 = "Hello" + " world"; Ergebnis ist Gleichheit: myString1 == "Hello world" |
(Identisch mit X++.) | Sowohl in X++ als auch in C# hängt das Verhalten des +-Operators vom Datentyp seiner Operanden ab. Der Operator verkettet Zeichenfolgen oder fügt Zahlen hinzu. |
mystring2 = "Hello"; myString2 += " world"; Ergebnis ist Gleichheit: myString2 == "Hello world" |
(Identisch mit X++.) | In X++ und C# sind die folgenden Anweisungen gleichwertig: a = a + b; a += b; |
Beispiel 3: Einbetten und Entfernen von Zeichenfolgentrennzeichen
Entweder einfache oder doppelte Anführungszeichen können zum Trennen von Zeichenfolgen in X++ verwendet werden. Das Escapezeichen (\) kann zum Einbetten von Trennzeichen in eine Zeichenfolge verwendet werden. Diese werden in der folgenden Tabelle veranschaulicht.
| X++ | C# | Kommentare |
|---|---|---|
myString1 = "They said \"yes\"."; Ergebnis: They said "yes". |
(Identisch mit X++.) | Mit dem Escapezeichen können Sie Zeichenfolgentrennzeichen in Zeichenfolgen einbetten. |
myString2 = 'They said "yes".'; Ergebnis: They said "yes". |
Die C#-Syntax lässt nicht zu, dass einfache Anführungszeichen Zeichenfolgen trennen. | Bei Zeichenfolgen, die vom Benutzer angezeigt werden können, wird es als bewährte Methode angesehen, das Escapezeichen anstelle der einfachen Anführungszeichen zu verwenden, wie im Beispiel gezeigt. |
myString3 = "They said 'yes'."; Ergebnis: They said 'yes'. |
(Identisch mit X++.) | In X++ werden die einfachen Anführungszeichen nicht als Trennzeichen behandelt, es sei denn, die Zeichenfolge beginnt mit einem einfachen Anführungszeichentrennzeichen. In C# hat das einfache Anführungszeichen keine besondere Bedeutung für Zeichenfolgen und kann nicht zum Trennen von Zeichenfolgen verwendet werden. In C# ist das einfache Anführungszeichen das erforderliche Trennzeichen für Literale des Typs System.Char. X++ hat keinen Zeichendatentyp. |
str myString4 = 'C'; Hier ist das einfache Anführungszeichen ein Zeichenfolgentrennzeichen. |
char myChar4 = 'C'; Hier ist das einfache Anführungszeichen ein System.Char Trennzeichen, kein System.String Trennzeichen. |
X++ hat keinen Datentyp, der in .NET Framework entspricht System.Char . Eine X++-Zeichenfolge, die auf eine Länge von 1 beschränkt ist, ist immer noch eine Zeichenfolge und kein Zeichendatentyp. |
Beispiel 4: Einzelnes Escapezeichen
Beispiele zur Veranschaulichung des einzelnen Escapezeichens in der Eingabe oder ausgabe sind in der folgenden Tabelle dargestellt.
| X++ | C# | Kommentare |
|---|---|---|
myString1 = "Red\ shoe"; Ergebnis: Red shoe |
Eine Literalzeichenfolge in C# darf nicht die zwei Zeichenfolge des Escapezeichens enthalten, gefolgt von einem Leerzeichen, z. B. "\". Es tritt ein Compilerfehler auf. | Wenn der X++-Compiler auf die zwei Zeichenreihen von "\" trifft, verwirft er das einzelne Escapezeichen. |
myString2 = "Red\\ shoe"; Ergebnis: Red\ shoe |
(Identisch mit X++.) | In einem Escapezeichenpaar negiert der erste die besondere Bedeutung des zweiten Zeichens. |
Vergleich: Arraysyntax
Es gibt Ähnlichkeiten und Unterschiede bei den Features und Syntax für Arrays in X++ im Vergleich zu C#.
Ähnlichkeiten
Insgesamt gibt es in der Syntax und Behandlung von Arrays in X++ und C# viel Ähnlichkeit. Es gibt jedoch viele Unterschiede.
Unterschiede
In der folgenden Tabelle sind Bereiche in der [] Syntax für Arrays aufgeführt, die für X++ und C# unterschiedlich sind.
| Kategorie | X++ | C# | Kommentare |
|---|---|---|---|
| Erklärung | Ein Array wird mit eckigen Klammern deklariert, die an den Variablennamen angefügt werden. | Ein Array wird mit eckigen Klammern deklariert, die an den Datentyp angefügt sind. | int myInts[]; // X++ Anmerkung: Ein X++-Array kann kein Parameter in einer Methode sein.
|
| Erklärung | Die Arraysyntax unterstützt nur primitive Datentypen, z int . B. und str. Die Syntax unterstützt keine Klassen oder Tabellen. |
Die Arraysyntax unterstützt primitive Datentypen und Klassen. | In X++ können Sie das Array Array für ein Array von Objekten verwenden. |
| Erklärung | X++ ist auf einzelne Dimensionarrays (myStrings[8]) beschränkt. | C# fügt Unterstützung für mehrdimensionale Arrays (myStrings[8,3]) und für gezapfte Arrays hinzu (myStrings[8][3]). | In X++ können Sie kein Array von Arrays haben. Es gibt jedoch eine erweiterte Syntax zum Einschränken der Menge an aktivem Arbeitsspeicher, die ein großes Array nutzen kann, was wie die mehrdimensionale Syntax in C#: int int intArray[1024,16]; aussieht. Weitere Informationen finden Sie unter Best Practice Performance Optimizations: Swapping Arrays to Disk. |
| Erklärung | In X++ ist ein Array ein spezielles Konstrukt, es handelt sich jedoch nicht um ein Objekt. | In C# sind alle Arrays Objekte, unabhängig von Syntaxvariationen. | X++ verfügt über eine Arrayklasse, der zugrunde liegende Mechanismus unterscheidet sich jedoch von Arrays, die mit der [] Syntax erstellt wurden. In C# verwenden alle Arrays denselben zugrunde liegenden Mechanismus, unabhängig davon, ob die [] Syntax der System.Array Klasse in Ihrem Code verwendet wird. |
| Length | In X++ wird die Länge eines Arrays in statischer Größe in der Deklarationssyntax bestimmt. | In C# wird die Größe eines Arrays bestimmt, wenn das Arrayobjekt erstellt wird. | Wenn Sie die [] Deklarationssyntax in X++ verwenden, ist keine weitere Vorbereitung erforderlich, bevor Sie dem Array Werte zuweisen. In C# müssen Sie das Array deklarieren und dann erstellen, bevor Sie es zuweisen. |
| Length | Ein X++-Array kann eine dynamische Länge aufweisen, die auch nach dem Starten der Population erhöht werden kann. Dies gilt nur, wenn das Array ohne Zahl innerhalb der [] deklariert wird. Die Leistung kann verlangsamt werden, wenn die Länge des dynamischen Arrays mehrmals erhöht wird. | In C# kann die Länge eines Arrays nach dem Festlegen der Länge nicht geändert werden. | Im folgenden Fragment von X++-Code ist nur das myInts Array dynamisch und kann die Größe vergrößern. int myInts[]; int myBools[5]; myInts[2] = 12; myInts[3] = 13; myBools[6] = 26; //Error |
| Length | Sie können die Länge einiger Arrays mithilfe der dimOf Funktion abrufen. |
C#-Arrays sind Objekte, die über eine Length Eigenschaft verfügen. |
Keine Kommentare. |
| Indizierung | Die Arrayindizierung basiert auf 1. | Die Arrayindizierung basiert auf 0. | mtIntArray[0] würde einen Fehler in X++ verursachen. |
| Dauerhaft | In X++ wird ein Konstantenwert am besten mithilfe der #define Präkompilerdirektive erreicht. | In C# können Sie die Variable-Deklaration mit dem Schlüsselwortkonstanten versehen, um einen konstanten Wert zu erzielen. | X++ hat kein Const-Schlüsselwort . C# kann Variablen, die mit der #define Präkompilerdirektive erstellt werden, keine Werte zuweisen. |
X++- und C#-Beispiele
Die folgenden Codebeispiele zeigen, wie Arrays von primitiven Datentypen behandelt werden. Das erste Beispiel befindet sich in X++, und das zweite Beispiel befindet sich in C#. Beide Proben erzielen dieselben Ergebnisse.
X++-Beispiel
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
Die Ausgabe im Infolog lautet wie folgt:
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#-Beispiel
using System;
public class Pgm_CSharp
{
static public void Main( string[] args )
{
new Pgm_CSharp().ArraySimple();
}
private void 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
Die Ausgabe des C#-Programms in der Befehlszeilenkonsole lautet wie folgt:
-------- 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]
Zusätzliche Array-ähnliche X++-Features
Der Container ist ein spezieller Datentyp, der in X++ verfügbar ist. Es kann als ähnlich wie ein Array oder eine Sammlung List angesehen werden.
Vergleich: Sammlungen
In einer Finanz- und Betriebsanwendung können Sie die X++ List -Sammlungsklasse verwenden. Das .NET Framework, das in C# verwendet wird, hat eine ähnliche Klasse namens System.Collections.Generic.List.
Vergleich der Verwendung der Listenklassen
In der folgenden Tabelle werden Methoden für die X++ List -Klasse mit den Methoden System.Collections.Generic.List aus .NET Framework und C# verglichen.
| Merkmal | X++ | C# | Kommentare |
|---|---|---|---|
| Deklaration der Sammlung | List myList; |
List<string> myList; |
Die X++-Deklaration enthält nicht den Typ der zu speichernden Elemente. |
| Deklaration des Iterators | ListIterator iterListEnumerator enumer; |
IEnumerator-Zeichenfolgen-Iter<>; | In X++ verfügt das ListIterator Objekt über Methoden, die insert und delete Elemente aus der List. X++ ListEnumerator kann den Inhalt der ListDatei nicht ändern. In X++ wird das ListEnumerator Objekt immer auf derselben Ebene wie die List. Dies gilt nicht immer für ListIterator. |
| Abrufen eines Iterators | new ListIterator (myList)myList.getEnumerator() |
myList.GetEnumerator() |
Sowohl in X++ als auch in C# verfügt das List-Objekt über eine Getter-Methode für einen zugeordneten Enumerator. |
| Konstruktor | new List(Types::String) |
new List<string>() |
Informationen zum Typ der Objekte, die in den List Klassen gespeichert werden sollen, werden dem Konstruktor sowohl in X++ als auch in C# zugewiesen. |
| Aktualisieren von Daten | Enumerator – der Enumerator wird ungültig, wenn elemente in der List Enumerator hinzugefügt oder entfernt werden.Iterator – der Iterator verfügt über Methoden zum Einfügen und Löschen von Elementen aus dem List. Der Iterator bleibt gültig. |
Enumerator – der Enumerator wird ungültig, wenn elemente in der List Enumerator hinzugefügt oder entfernt werden. |
Enumeratoren werden ungültig, nachdem Elemente aus dem ListX++- und C#-Element hinzugefügt oder gelöscht wurden. |
| Aktualisieren von Daten | In X++ verfügt die List Klasse über Methoden zum Hinzufügen von Elementen am Anfang oder Ende der Liste. |
In C# verfügt die List Klasse über Methoden zum Hinzufügen von Mitgliedern an einer beliebigen Position in der Liste. Außerdem gibt es Methoden zum Entfernen von Elementen an jeder Position. |
In X++-Elementen kann nur List von einem Iterator entfernt werden. |
Beispiel 1: Deklaration einer Liste
Die folgenden Codebeispiele sind in X++ und C# enthalten, die Sammlungen deklarieren List .
// X++
List listStrings ,list2 ,listMerged;
ListIterator literator;
// C#
using System;
using System.Collections.Generic;
List<string> listStrings ,list2 ,listMerged; IEnumerator<string> literator;
Beispiel 2: Erstellen einer Liste
In beiden Sprachen muss der Typ der Elemente, die in den Sammlungsspeichern gespeichert werden, zum Zeitpunkt der Erstellung angegeben werden. Für Klassentypen kann X++ nicht spezifischer abrufen, als ob es sich bei dem Typ um eine Klasse (Types::Class) handelt. Die folgenden Codebeispiele sind in X++ und C# enthalten.
// X++
listStrings = new List( Types::String );
// C#
listStrings = new List<string>;
Beispiel 3: Hinzufügen von Elementen zu einer Liste
In X++ und C# stellt die Auflistung eine Methode zum Anfügen eines Elements an das Ende der Auflistung und zum Einfügen eines Elements am Anfang bereit. In C# stellt die Auflistung eine Methode zum Einfügen an einem beliebigen Punkt in der Auflistung basierend auf einem Indexwert bereit. In X++ kann ein Sammlungs-Iterator ein Element an seiner aktuellen Position einfügen. Die folgenden Codebeispiele sind in X++ und C# enthalten.
// X++
listStrings.addEnd ("StringBB.");
listStrings.addStart ("StringAA.");
// Iterator performs a midpoint insert at current position.
listIterator.insert ("dog");
// C#
listStrings.Add ("StringBB.");
listStrings.Insert (0 ,"StringAA.");
// Index 7 determines the insertion point.
listStrings.Insert (7 ,"dog");
Beispiel 4: Durchlaufen einer Liste
Sowohl X++ als auch C# verfügen über Iteratorklassen, mit denen Sie die Elemente in einer Auflistung schrittweise durchlaufen können, wie in den folgenden Beispielen gezeigt.
// X++
literator = new ListIterator (listStrings);
// Now the iterator points 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();
}
// C#
literator = listStrings .GetEnumerator();
// Now enumerator points before the first item, not at the first item.
// 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);
}
Beispiel 4b: Foreach in C#
In C# wird das Schlüsselwort foreach häufig verwendet, um die Aufgabe der Iterierung durch eine Liste zu vereinfachen. Im folgenden Codebeispiel verhält sich dasselbe wie im vorherigen C#-Beispiel.
foreach (string currentString in listStrings)
{
Console.WriteLine(currentString);
}
Beispiel 5: Löschen des zweiten Elements
Die folgenden Codebeispiele löschen das zweite Element aus der Auflistung. In X++ erfordert dies einen Iterator. In C# stellt die Auflistung selbst die Methode zum Entfernen eines Elements bereit.
// X++
literator.begin();
literator.next();
literator.delete();
// C#
listStrings.RemoveAt(1);
Beispiel 6: Kombinieren von zwei Auflistungen
Die folgenden Codebeispiele kombinieren den Inhalt von zwei Auflistungen in einer Auflistung.
// X++
listStrings = List::merge(listStrings ,listStr3);
// Or use the .appendList method:
listStrings.appendList (listStr3);
// C#
listStrings.InsertRange(listStrings.Count ,listStr3);
Vergleich: Sammlungen von Schlüsseln mit Werten
In einer Finanz- und Betriebsanwendung können Sie die Map Sammlungsklasse verwenden. Die Map Auflistung enthält Wertepaare, den Schlüsselwert plus einen Datenwert. Dies ähnelt der .NET Framework-Klasse mit dem Namen System.Collections.Generic.Dictionary.
Ähnlichkeiten
In der folgenden Liste werden Ähnlichkeiten zwischen X++ und C# hinsichtlich ihrer Sammlungen beschrieben, die Schlüsselwertpaare speichern:
- Beide verhindern doppelte Schlüssel.
- Beide verwenden einen Enumerator (oder Iterator), um die Elemente zu durchlaufen.
- Beide Schlüsselwertauflistungsobjekte werden mit Bezeichnungen der Typen erstellt, die als Schlüssel und Wert gespeichert werden.
- Beide können Klassenobjekte speichern und sind nicht auf das Speichern von Grundtypen wie Int beschränkt.
Unterschiede
In der folgenden Tabelle werden die Unterschiede zwischen X++ und C# in Bezug auf die Auflistungsklassen beschrieben, die Schlüsselwertpaare speichern:
| Merkmal | X++ | C# | Kommentare |
|---|---|---|---|
| Duplizieren von Schlüsseln | In X++ verhindert die Map Klasse doppelte Schlüssel, indem der Aufruf der insert Methode implizit als Vorgang behandelt wird, um nur den dem Schlüssel zugeordneten Wert zu aktualisieren. |
In C# löst die Dictionary Klasse eine Ausnahme aus, wenn Sie versuchen, einen doppelten Schlüssel hinzuzufügen. |
Doppelte Schlüssel werden in beiden Sprachen verhindert, obwohl es sich um unterschiedliche Techniken handelt. |
| Elemente löschen | In X++ wird die delete Methode für ein Iteratorobjekt verwendet, um ein unerwünschtes Schlüssel-Wert-Paar aus einem Map. |
In C# weist die Dictionary Klasse eine remove Methode auf. |
In beiden Sprachen wird ein Enumerator ungültig gemacht, wenn die Sammlungselementanzahl während der Lebensdauer des Enumerators geändert wird. |
Beispiel 1: Deklaration einer Key-Value-Auflistung
In beiden Sprachen muss der Typ der Elemente, die von den Schlüsselwertauflistungsspeichern gespeichert werden, angegeben werden. In X++ wird der Typ zum Zeitpunkt der Konstruktion angegeben. In C# wird der Typ sowohl zum Zeitpunkt der Deklaration als auch zum Zeitpunkt der Konstruktion angegeben. Die folgenden Codebeispiele sind in X++ und C# enthalten.
// X++
Map mapKeyValue;
MapEnumerator enumer;
MapIterator mapIter;
// C#
Dictionary<int,string> dictKeyValue;
IEnumerator<SysCollGen.KeyValuePair<int,string>> enumer;
KeyValuePair<int,string> kvpCurrentKeyValuePair;
Beispiel 2: Erstellen der Auflistung
In beiden Sprachen wird der Typ der Elemente, die von der Schlüsselwertauflistung während der Erstellung angegeben werden, gespeichert. Für Klassentypen kann X++ nicht spezifischer abrufen, als ob es sich bei dem Typ um eine Klasse (Types::Class) handelt. Die folgenden Codebeispiele sind in X++ und C# enthalten.
// X++
mapKeyValue = new Map(Types::Integer, Types::String);
// C#
dictKeyValue = new Dictionary<int,string>();
Beispiel 3: Hinzufügen eines Elements zur Auflistung
Es gibt fast keinen Unterschied darin, wie ein Element einer Schlüsselwertauflistung in X++ und C# hinzugefügt wird, wie in den folgenden Codebeispielen gezeigt.
// X++
mapKeyValue.insert(xx ,int2str(xx) + “_Value”);
// C#
dictKeyValue.Add(xx ,xx.ToString() + “_Value”);
Beispiel 4: Durchlaufen einer Key-Value Auflistung
Enumeratoren werden verwendet, um die Schlüsselwertauflistungen sowohl in X++ als auch in C# zu durchlaufen, wie in den folgenden Codebeispielen gezeigt.
// X++
enumer = mapKeyValue.getEnumerator();
while (enumer.moveNext())
{
iCurrentKey = enumer.currentKey();
sCurrentValue = enumer.currentValue();
// Display key and value here.
}
// C#
enumer = dictKeyValue.GetEnumerator();
while (enumer.MoveNext())
{
kvpCurrentKeyValuePair = enumer.Current;
// Display .Key and .Value properties=
// of kvpCurrentKeyValuePair here.
}
Beispiel 5: Aktualisieren des werts, der einem Schlüssel zugeordnet ist
Die Syntax unterscheidet sich sehr zwischen den beiden Sprachen für eine Aktualisierung des Werts, der einem bestimmten Schlüssel zugeordnet ist. Die Ollowing-Codebeispiele beziehen sich auf den Schlüssel 102.
// X++
mapKeyValue.insert(
102 ,
”.insert(), Re-inserted” + ” key 102 with a different value.”);
// C#
dictKeyValue[102] =
“The semi-hidden .item property in C#, Updated the value for key 102.”;
Beispiel 6: Löschen eines Elements
Die Syntax unterscheidet sich zwischen den beiden Sprachen, um ein Schlüssel-Wert-Paar aus einer Auflistung zu löschen, während die Auflistungselemente durchlaufen werden. Codebeispiele für den Schlüssel 102 finden Sie unten.
// X++
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();
}
// C#
dictKeyValue.Remove(104);
Vergleich: Ausnahmen
Es gibt einige Ähnlichkeiten, aber viele Unterschiede beim Vergleichen des Ausnahmeverhaltens zwischen X++ und C#. Die Schlüsselwörter "Try", " Catch" und "Throw " verhalten sich in X++ und C# gleich. Die Arten von ausgelösten und abgefangenen Ausnahmen unterscheiden sich jedoch für die beiden Sprachen.
Ähnlichkeiten
Ähnlichkeiten zwischen X++ und C# bezüglich ihrer Ausnahmefeatures sind die folgenden Beispiele:
- Beide Sprachen haben dasselbe Try-Schlüsselwort .
- Beide weisen dasselbe Catch-Schlüsselwort auf.
- Beide aktivieren eine Catch-Anweisung , die keine bestimmte Ausnahme angibt. Eine solche Catch-Anweisung erfasst alle Ausnahmen, die sie erreichen.
- Beide weisen dasselbe Throw-Schlüsselwort auf .
Unterschiede
Ausnahmebezogene Unterschiede zwischen X++ und C# werden in der folgenden Tabelle beschrieben.
| Merkmal | X++ | C# | Kommentare |
|---|---|---|---|
| wiederholen | Springt zur ersten Anweisung im zugeordneten Try-Block . Weitere Informationen finden Sie unter "Ausnahmebehandlung mit "Try and catch Keywords". | Die Funktionalität des Schlüsselworts "Wiederholung " kann im C#-Code nachgeahmt werden, aber es gibt kein entsprechendes Schlüsselwort. | Nur X++ hat ein Wiederholungsstichwort . C# hat kein Gegenstück. Weitere Informationen finden Sie unter X++, C#-Vergleich: Automatische Wiederholung nach einer Ausnahme. |
| endlich | Das finally Schlüsselwort wird unterstützt, um den Schlüsselwörtern try zu catch folgen. |
Das letzte Schlüsselwort markiert einen Codeblock, der den Try - und Catch-Blöcken folgt. Der Schluss wird unabhängig davon ausgeführt, ob eine Ausnahme ausgelöst oder abgefangen wird. | Die Semantik ist identisch mit der Semantik in C#. |
| Bestimmte Ausnahmen | In X++ ist eine Ausnahme ein Element der Exception Enumeration, z. B. Error, Deadlock oder CodeAccessSecurity. Keine Ausnahme kann eine andere enthalten. |
In C# ist eine Ausnahme eine Instanz der System.Exception Basisklasse oder eine beliebige Klasse, die von ihr erbt. Eine Ausnahme kann in der InnerException Eigenschaft der ausgelösten Ausnahme enthalten sein. |
In X++ ist jede ausgelöste Ausnahme ein Wert der Exception-Enumeration. Weitere Informationen finden Sie unter Exception Enumeration. |
| Ausnahmemeldung | In X++ ist die Nachricht, die erstellt wird, wenn eine Ausnahme ausgelöst wird, nur im Infolog verfügbar, und die Nachricht ist nicht direkt mit der Ausnahme verknüpft. | In C# ist die Nachricht das Message Element des System.Exception Objekts. |
In X++ ist die Methode "Global::error" der Mechanismus, mit dem Ausnahmemeldungen im Infolog angezeigt werden. Weitere Informationen finden Sie unter "Ausnahmebehandlung mit "Try and catch Keywords". |
| Ausnahmebedingungen | In X++ tritt ein Fehler auf, wenn Sie eine Instanzmethode für eine Objektvariable aufrufen, der noch nichts zugewiesen wurde. Es wird jedoch keine Ausnahme zusammen mit diesem Fehler ausgelöst. Daher kann kein catch Block die Kontrolle erlangen, auch wenn die nicht zugewiesene Variable in einem try Block missbraucht wird. Im folgenden Codebeispiel bewirkt der durch den Code box4.toString(); verursachte Fehler keine Übertragung des Steuerelements in einen block catch : 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."); |
In C# wird a System.NullReferenceException ausgelöst, wenn eine nicht initialisierte Variable als Objektverweis behandelt wird. |
Möglicherweise gibt es mehrere andere Unterschiede in den Bedingungen, die Ausnahmen auslösen. |
| SQL-Transaktionen | In X++ wenn eine SQL-Ausnahme in einer ttsBegin - ttsCommit-Transaktion auftritt, kann keine Catch-Anweisung innerhalb des Transaktionsblocks die Ausnahme verarbeiten. | In C# kann ein Catch-Block in einer SQL-Transaktion die Ausnahme abfangen. |
Examples
Die folgenden X++-Features werden veranschaulicht:
- try keyword.
- Catch-Schlüsselwort .
- Das Verhalten nach einer Ausnahme::Fehler-Ausnahme tritt auf.
X++-Beispiel
// X++
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 doesn't appear in the Infolog," + " it's 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's in C#.");
//}
info("End of program.");
}
Output
Hier sehen Sie die Ausgabe aus dem Infolog-Fenster:
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#-Beispiel
Das folgende C#-Programm ist eine Neuschreibung des vorherigen X++-Programms.
// C#
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 doesn't appear in the Infolog, it's 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's in C#.");
}
Console.WriteLine("End of program.");
}
} // EOClass
Output
Dies ist die Ausgabe in der C#-Konsole:
(e2) In catch block for -- System.IndexOutOfRangeException
'finally' is not an X++ keyword, although it's in C#.
End of program.
Vergleich: Automatische Wiederholung nach einer Ausnahme
Manchmal können Sie Code in einem Catch-Block schreiben, der die Ursache einer Ausnahme behebt, die während der Laufzeit auftritt. X++ stellt ein Wiederholungsstichwort bereit, das nur innerhalb eines Catch-Blocks verwendet werden kann. Mit dem Schlüsselwort "Wiederholen " kann ein Programm zum Anfang des Try-Blocks zurückkehren, nachdem das Problem durch Code im Catch-Block behoben wurde. C# verfügt nicht über ein Wiederholungsstichwort . C#-Code kann jedoch geschrieben werden, um ein entsprechendes Verhalten bereitzustellen.
Codebeispiele für Wiederholungen
Das folgende X++-Beispielprogramm bewirkt, dass eine Ausnahme::Fehler ausgelöst wird. Dies tritt auf, wenn zuerst versucht wird, ein Element aus dem sStrings Array mithilfe eines ungültigen Indexwerts zu lesen. Wenn die Ausnahme abgefangen wird, wird während der Laufzeit innerhalb des Catch-Blocks Korrekturmaßnahmen ergriffen. Die Wiederholungsanweisung springt dann zurück zur ersten Anweisung im Try-Block . Diese zweite Iteration funktioniert ohne Ausnahme.
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
Hier sehen Sie die Ausgabe im Fenster "Drucken":
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#-Beispiel
Das folgende C#-Beispiel ist keine Zeilenübersetzung aus dem vorherigen X++-Beispiel. Stattdessen weist das C#-Programm eine andere Struktur auf, sodass es das Verhalten des Wiederholungsstichworts nachahmt, auf dem das X++-Programm basiert. Die Try - und Catch-Blöcke befinden sich in einer aufgerufenen Methode. Die Variablen, die im Try-Block verwendet werden, werden in der Aufrufermethode gespeichert. Die Aufrufermethode übergibt die Variablen als Parameter, die mit dem Ref-Schlüsselwort versehen sind, sodass ihre Werte innerhalb des Catch-Blocks der aufgerufenen Methode korrigiert werden können. Die aufgerufene Methode erfasst alle Ausnahmen und gibt einen booleschen Wert zurück, der an den Aufrufer zurückgibt, ob ein zweiter Aufruf erforderlich ist.
// C#
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
Dies ist die Ausgabe in der Konsole:
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.
Vergleich: Operatoren
In diesem Abschnitt werden die Operatoren zwischen X++ und C# verglichen.
Zuordnungsoperatoren
In der folgenden Tabelle werden die Unterschiede zwischen den Zuordnungsoperatoren in X++ und C# angezeigt.
| X++ und C# | Unterschiede |
|---|---|
= |
In X++ verursacht dieser Operator eine implizite Konvertierung, wenn ein Genauigkeitsverlust auftreten kann, z. B. für eine Zuordnung von einem Int64 zu einem Int. In C# verursacht die Zuordnung jedoch einen Kompilierungsfehler. |
+= und -= |
Der einzige Unterschied besteht darin, dass diese Operatoren in C# auch bei der Stellvertretungsmanipulation verwendet werden. |
| ++ und -- | Dies sind die Inkrementierungs- und Dekrementoperatoren in beiden Sprachen. Die folgende Zeile ist in beiden Sprachen identisch:++myInteger;In X++ gelten diese beiden Operatoren jedoch für Anweisungen, nicht für Ausdrücke. Daher generieren die folgenden Zeilen Kompilierungsfehler in X++: myStr = int2str(++myInteger);myIntA = myIntBB++; |
Arithmetische Operatoren
Die folgende Tabelle listet die arithmetischen Operatoren auf.
| X++ und C# | Unterschiede |
|---|---|
| * | Als Multiplikationsoperator gibt es keine Unterschiede. Anmerkung: Das Sternchen wird auch in den SQL-Anweisungen verwendet, die Teil der X++-Sprache sind. In diesen SQL-Anweisungen kann das Sternchen auch eine der folgenden sein:
|
/ |
Der Divisionsoperator ist in X++ und C# identisch. |
MOD |
Bei Modulo-Vorgängen besteht der einzige Unterschied darin, dass das %-Symbol in C# verwendet wird. |
| + | Der Additionsoperator ist in X++ und C# identisch. Das Pluszeichen wird auch für die Zeichenfolgenverkettung verwendet. Dieser Operator fügt Zahlen hinzu und verkettet Zeichenfolgen in beiden Sprachen. |
| - | Der Subtraktionsoperator ist in X++ und C# identisch. |
Bitweise Operatoren
In der folgenden Tabelle werden die bitweisen Operatoren zwischen X++ und C# verglichen.
| X++ und C# | Unterschiede |
|---|---|
| << | Der linke Schichtoperator ist in X++ und C# identisch. |
| >> | Der Rechte Umschaltoperator ist in X++ und C# identisch. |
| ~ | Der bitweise NOT-Operator ist in X++ und C# identisch. |
| & | Der binäre AND-Operator ist in X++ und C# identisch. |
| ^ | Der binäre XOR-Operator ist in X++ und C# identisch. |
Relationale Operatoren
Die folgenden relationalen Operatoren sind in X++ und C# identisch:
==<=<=><!=&&||!? :
Vergleich: Ereignisse
Es gibt einige Unterschiede bei der Implementierung des Ereignisentwurfsmusters durch X++ und C#. Weitere Informationen finden Sie unter Ereignisterminologie und Schlüsselwörter.
Vergleich von Ereignissen zwischen X++ und C#
Es gibt Unterschiede in der Art und Weise, wie Stellvertretungen für Ereignisse in X++ und C# verwendet werden.
| Begriff | X++ | C# | Kommentare |
|---|---|---|---|
| delegate | In X++ kann eine Stellvertretung nur als Mitglied einer Klasse deklariert werden. Eine Stellvertretung kann kein Mitglied einer Tabelle sein. Alle Stellvertretungen sind Instanzenmitglieder ihrer Klasse, nicht statische Member. Für eine Delegatdeklaration kann kein Zugriffsmodifizierer verwendet werden, da alle Stellvertretungen geschützte Member sind. Daher kann das Ereignis nur durch Code innerhalb derselben Klasse ausgelöst werden, in der der Delegat Mitglied ist. Eine Ausnahme von der privaten Natur eines Delegaten besteht jedoch darin, dass Code außerhalb der Klasse mithilfe der Operatoren += und -= für die Stellvertretungen verwendet werden kann. | In C# ist jeder Delegat ein Typ, genauso wie jede Klasse ein Typ ist. Ein Delegat wird unabhängig von jeder Klasse deklariert. Ohne das Ereignisschlüsselwort können Sie einen Delegaten als Parametertyp für eine Methode verwenden, genauso wie Sie eine Klasse als Parametertyp haben können. Sie können eine Instanz eines Delegaten erstellen, die für den Parameterwert übergeben werden soll. | In X++ ist jede Klasse ein Typ, aber kein Delegat ist ein Typ. Sie können keine Instanz eines Delegaten erstellen. Kein Delegat kann ein Parameter für eine Methode sein. Sie können jedoch eine Klasse erstellen, die über ein Delegatelement verfügt, und Sie können Instanzen der Klasse als Parameterwerte übergeben. Weitere Informationen finden Sie unter X++-Schlüsselwörter. |
| Ereignis | In X++-Code ist ein Ereignis einer der folgenden:
|
In C# wird das Ereignisschlüsselwort verwendet, um einen Delegattyp als Mitglied einer Klasse zu deklarieren. Der Effekt des Ereignisschlüsselworts besteht darin, die Stellvertretung geschützt zu machen, aber dennoch für die Operatoren += und -= zugänglich zu machen. Sie können Ereignishandlermethoden für ein Ereignis abonnieren, indem Sie den Operator += verwenden. Ein Delegat kann ohne das Ereignisstichwort als Technik zum Übergeben eines Funktionszeigers als Parameter an eine Methode nützlich sein. | Die automatischen Ereignisse, die vor dem Start einer Methode und nach dem Ende einer Methode auftreten, können nur mithilfe des AOT abonniert werden. |
| += und -= Operatoren | In X++ verwenden Sie den Operator += zum Abonnieren von Methoden für einen Delegaten. Der Operator -= gekündigt eine Methode von einer Stellvertretung. | In C# verwenden Sie den Operator += zum Abonnieren von Methoden für ein Ereignis oder einen Delegaten , der nicht mit dem Ereignisschlüsselwort verwendet wird. | Der Delegat enthält einen Verweis auf alle Objekte mit Methoden, die den Delegaten abonniert haben. Diese Objekte sind für die Garbage Collection nicht berechtigt, während Stellvertretung diese Verweise enthält. |
eventHandler |
In X++ ist das Ereignishandler-Schlüsselwort erforderlich, wenn Sie entweder den Operator += oder -= verwenden, um eine Methode von einem Delegaten zu abonnieren oder abzubestellen. |
System.EventHandler ist ein Delegattyp in .NET Framework. |
Dieser Begriff wird in X++ anders verwendet als in C# oder .NET Framework. Weitere Informationen finden Sie unter X++-Schlüsselwörter. |
X++-Beispiel
Die wichtigsten Punkte, die Sie beachten müssen, sind im X++-Beispiel folgendes:
Das Hat
XppClassein Delegatmitglied, das benanntmyDelegateist.Hinweis
Das AOT enthält einen Knoten für den Delegaten. Der Knoten befindet sich unter AOT > Classes > XppClass > myDelegate. Mehrere Ereignishandlerknoten können sich unter dem MyDelegate-Knoten befinden. Ereignishandler, die durch Knoten im AOT dargestellt werden, können während der Laufzeit nicht vom Operator -= entfernt werden.
Die {} geschweiften Klammern am Ende der Stellvertretungsdeklaration sind erforderlich, können aber keinen Code enthalten.
Dies
XppClasshat zwei Methoden, deren Parametersignaturen mit dem Delegaten kompatibel sind. Eine Methode ist statisch.Die beiden kompatiblen Methoden werden dem Delegaten mit dem Operator += und dem EventHandler-Schlüsselwort hinzugefügt. Diese Anweisungen rufen nicht die Ereignishandlermethoden auf, die Anweisungen fügen nur die Methoden zum Delegaten hinzu.
Das Ereignis wird durch einen Aufruf der Stellvertretung ausgelöst.
Der Parameterwert, der an den Delegaten übergeben wird, wird von jeder Ereignishandlermethode empfangen.
Der kurze X++-Auftrag oben im Beispiel startet den Test.
// X++
// Simple job to start the delegate event test.
static void DelegateEventTestJob()
{
XppClass::runTheTest("The information from the X++ job.");
}
// The X++ class that contains the delegate and the event handlers.
class XppClass
{
delegate void myDelegate(str _information)
{
}
public void myEventSubscriberMethod2(str _information)
{
info("X++, hello from instance event handler 2: " + _information);
}
static public void myEventSubscriberMethod3(str _information)
{
info("X++, hello from static event handler 3: " + _information);
}
static public void runTheTest(str _stringFromJob)
{
XppClass myXppClass = new XppClass();
// Subscribe two event handler methods to the delegate.
myXppClass.myDelegate += eventHandler(myXppClass.myEventSubscriberMethod2);
myXppClass.myDelegate += eventHandler(XppClass::myEventSubscriberMethod3);
// Raise the event by calling the delegate one time,
// which calls all the subscribed event handler methods.
myXppClass.myDelegate(_stringFromJob);
}
}
Die Ausgabe des vorherigen X++-Auftrags lautet wie folgt:
X++, hello from static event handler
3: The information from the X++ job. X++, hello from instance event handler
2: The information from the X++ job.
C#-Beispiel
Dieser Abschnitt enthält ein C#-Codebeispiel für das Ereignisentwurfsmuster des vorherigen X++-Beispiels.
// C#
using System;
// Define the delegate type named MyDelegate.
public delegate void MyDelegate(string _information);
public class CsClass
{
protected event MyDelegate MyEvent;
static public void Main()
{
CsClass myCsClass = new CsClass();
// Subscribe two event handler methods to the delegate.
myCsClass.MyEvent += new MyDelegate(myCsClass.MyEventSubscriberMethod2);
myCsClass.MyEvent += new MyDelegate(CsClass.MyEventSubscriberMethod3);
// Raise the event by calling the event one time, which
// then calls all the subscribed event handler methods.
myCsClass.MyEvent("The information from the C# Main.");
}
public void MyEventSubscriberMethod2(string _information)
{
Console.WriteLine("C#, hello from instance event handler 2: " + _information);
}
static public void MyEventSubscriberMethod3(string _information)
{
Console.WriteLine("C#, hello from static event handler 3: " + _information);
}
}
Die Ausgabe aus dem vorherigen C#-Beispiel lautet wie folgt:
CsClass.exe C#, hello from instance event handler
2: The information from the C\# Main. C\#, hello from static event handler
3: The information from the C\# Main.
Ereignisse und das AOT
Es gibt andere Ereignissysteme, die nur für Elemente im AOT gelten. Weitere Informationen finden Sie unter Ereignishandlerknoten im AOT.
Vergleich: Präkompilerdirektiven
X++ und C# teilen einige Schlüsselwörter für ihre Präkompilerdirektivesyntax, aber die Bedeutungen sind nicht immer identisch.
Ähnlichkeiten
Die X++- und C#-Compiler erkennen viele der gleichen Schlüsselwörter. In den meisten Fällen bedeuten die Schlüsselwörter für beide Sprachcompiler das gleiche.
Unterschiede
Ein grundlegender Unterschied zwischen den Präcompilerdirektiven in X++ und C# ist das #define Schlüsselwort, das beide Sprachvorkompilierer erkennen. Im Gegensatz zu C# erfordert die #define direktive in X++ einen Punkt in der Syntax. In X++ können Klammern verwendet werden, um dem definierten Symbol einen Wert zuzuweisen. Diese Unterschiede werden in den folgenden Beispielen gezeigt:
- In X++: #define. InitialYear(2003)
- In C#: #define InitialYear
Ein kleiner Unterschied besteht darin, dass in C# Leerzeichen und Tabstoppzeichen zwischen dem #-Zeichen und dem Direktive-Schlüsselwort vorhanden sein können, z. B. #define Testing.
Identische Schlüsselwörter
In der folgenden Tabelle sind Präkompilerdirektiven aufgeführt, die in X++ und C# ähnlich sind.
| Keyword | X++ | C# | Kommentare |
|---|---|---|---|
#define |
In X++ kann ein Vorkompilervariablenname definiert werden, und dieser Variablen kann ein Wert zugewiesen werden. | In C# kann ein Vorkompilervariablenname definiert werden, dieser Variablen kann jedoch kein Wert zugewiesen werden. Darüber hinaus müssen alle #define in C# oben in der Datei auftreten und können nach code wie einer using-Anweisung oder einer Klassendeklaration nicht auftreten. | Der C#-Compiler kann einen Befehlszeilenparameter /define eingeben, um einen Vorkompilervariablennamen zu definieren, ohne die Variable in einer C#-Codedatei zu definieren. Der X++-Compiler hat kein Gegenstück zu /define. |
#if |
In X++ kann #if bestimmen, ob eine Vorkompilervariable vorhanden ist und ob die Variable einen bestimmten Wert aufweist. | In C# kann #if nur bestimmen, ob eine Vorkompilervariable vorhanden ist. Es kann nicht auf einen Wert getestet werden, da kein Wert zugewiesen werden kann. | |
#endif |
In X++ markiert #endif das Ende eines #if Blocks. Außerdem wird ein #ifnot Block beendet. | In C# markiert #endif das Ende eines #if Blocks, unabhängig davon, ob der Block eine #else enthält. |
Verschiedene Schlüsselwörter mit demselben Verarbeitungsergebnis
In der folgenden Tabelle sind Präkompilerdirektiven aufgeführt, die in X++ und C# unterschiedlich benannt werden, die jedoch bei der Verarbeitung dieselben Ergebnisse liefern.
| X++ | C# | Kommentare |
|---|---|---|
| #ifnot | #if #else | In X++ gibt es keine #else Direktive, aber die #ifnot bietet ähnliche Funktionen. In X++ können #ifnot bestimmen, ob eine Vorkompilervariable vorhanden ist und ob die Variable keinen bestimmten bestimmten Wert aufweist. In C# kann #if bestimmen, ob eine Vorkompilervariable vorhanden ist, wenn "!" dem Variablennamen wird das Symbol vorangestellt. |
//BP Deviation documented |
#pragma Warnung | Diese X++- und C#-Einträge sind nicht gleichwertig, aber es gibt eine teilweise Ähnlichkeit. Beide unterdrücken Compilerwarnungen. |
| #macrolib | . HPP-Datei in C++ | Es gibt eine teilweise Ähnlichkeit zwischen der X++-Direktive #macrolib und einem . HPP-Datei in C++. Beide können mehrere #define-Anweisungen enthalten. |
Vorkompilierungsdirektiven ausschließlich für X++
In der folgenden Tabelle sind X++-Vorkompilierdirektiven aufgeführt, die kein direktes Gegenstück in C# aufweisen.
| X++ | Kommentare |
|---|---|
| #linenumber | Die #linenumber-Direktive dient zum Abrufen der Zeilennummer, sodass sie in den Infolog ausgegeben werden kann. Die C#-Direktive #line unterscheidet sich, da sie zum Festlegen der Zeilennummer dient. |
| #defdec #definc | |
| #globaldefine | In X++ gibt es einen kleinen Unterschied zwischen #globaldefine und #define. Der Unterschied besteht darin, dass #globaldefine niemals einen aktuellen Nichtnullwert überschreibt, der einer Vorkompilervariablen durch #define zugewiesen wurde. C# hat nichts ähnliches wie dieser Unterschied, da in C# kein Vorkompilervariablenname zugewiesen werden kann. |
| #localmacro #macro | In X++ können Sie #localmacro einer Vorkompilierungsvariablen einen Mehrzeilenwert zuweisen. #macro ist ein Synonym, aber #localmacro wird empfohlen. In C# verfügt die #define-Direktive über einen Teil dieser Funktionalität, kann jedoch keinem Vorkompilierervariablen einen Wert zuweisen. |
| #globalmacro | In X++ ist #globalmacro fast identisch mit der bevorzugten #localmacro. |
Vergleich: Objektorientierte Programmierung
Die objektorientierten Programmierprinzipien (OOP) von X++ unterscheiden sich von C#.
Konzeptionelle Vergleiche
In der folgenden Tabelle wird die Implementierung von OOP-Prinzipien zwischen X++ und C# verglichen.
| Merkmal | X++ | C# | Kommentare |
|---|---|---|---|
| Guss | Die X++-Sprache weist die Schlüsselwörter auf und wie, die verwendet werden, um Downcasts sicher und explizit zu machen. Tipp: X++ erfordert nicht die Verwendung des Schlüsselworts , wenn Sie eine Basisklassenvariable auf eine abgeleitete Klassenvariable heruntercasten. Es wird jedoch empfohlen, dass alle Downcast-Anweisungen das Schlüsselwort verwenden. | Ein Objekt kann entweder nach oben oder unten in den Vererbungspfad umwandeln. Downcasts erfordern das Schlüsselwort . | Weitere Informationen zu den X++-Schlüsselwörtern findenSie unter Expression Operators: Is and As for Inheritance. |
| Lokale Funktionen | Eine Methode kann eine Deklaration und einen Codetext für null oder mehr lokale Funktionen enthalten. Nur diese Methode kann Aufrufe der lokalen Funktion haben. | C# 3.0 unterstützt Lambda-Ausdrücke, die einige Ähnlichkeiten mit anonymen Funktionen und lokalen Funktionen aufweisen. Lambda-Ausdrücke werden häufig mit Stellvertretungen verwendet. | |
| Methodenüberladung | Methodenüberladungen werden nicht unterstützt. Ein Methodenname kann nur einmal pro Klasse auftreten. | Die Methodenüberladung wird unterstützt. Ein Methodenname kann mehrmals in einer Klasse mit unterschiedlichen Parametersignaturen in jedem Fall auftreten. | X++ unterstützt optionale Parameter für Methoden. Optionale Parameter können die Methodenüberladung teilweise imitieren. Weitere Informationen finden Sie in der Zeile für optionale Parameter in dieser Tabelle. |
| Methodenüberschreibung | Methodenüberschreibung wird unterstützt. Eine abgeleitete Klasse kann eine Methode mit demselben Namen wie in der Basisklasse haben, solange die Parametersignatur in beiden Fällen identisch ist. Die einzige Ausnahme besteht darin, dass die Außerkraftsetzungsmethode einem Parameter einen Standardwert hinzufügen kann. | Methodenüberschreibung wird unterstützt. Das virtuelle Schlüsselwort muss auf eine Methode angewendet werden, bevor die Methode in einer abgeleiteten Klasse überschrieben werden kann. | Das Konzept der Außerkraftsetzung einer Methode umfasst den Methodennamen, die Parametersignatur und den Rückgabetyp. Das Konzept der Methodenüberschreibung gilt nicht, wenn sich die Basismethode und die Überschreibungsmethode in einem dieser Aspekte unterscheiden. |
| Optionale Parameter | Auf eine Parameterdeklaration kann eine Standardwertzuweisung folgen. Der Methodenaufrufer hat die Möglichkeit, einen Wert für diesen Parameter zu übergeben oder den Parameter zu ignorieren, um den Standardwert zu akzeptieren. Dieses Feature imitiert Methodenüberladungen, da zwei Aufrufe desselben Methodennamens unterschiedliche Anzahl von Parametern übergeben können. Jeder Parameter mit einem Standardwert muss dem letzten Parameter folgen, der keinen Standardwert aufweist. | Optionale Parameter werden vom Params-Schlüsselwort unterstützt. Auch ohne das Params-Schlüsselwort kann die Methodenüberladung aus Sicht des Aufrufers teilweise ähnliche Funktionen bieten. | Weitere Informationen finden Sie unter "Parameter" und "Bereichsdefinition" und "Verwenden optionaler Parameter". |
| Einzelne Vererbung | Sie können Ihre X++-Klasse von einer anderen X++-Klasse ableiten, indem Sie das Schlüsselwort "erweitert " im Klassenknoten "classDeclaration" der Klasse im AOT verwenden. Keine Klasse wird implizit direkt von einer anderen Klasse abgeleitet. Wenn Ihre Klasse direkt von der Object Klasse abgeleitet werden soll, müssen Sie das Schlüsselwort "erweitert" verwenden. Sie können nur eine Klasse für das Schlüsselwort "erweitert " angeben.Achtung: Wenn Sie eine X++-Basisklasse ändern, von der andere Klassen abgeleitet sind, müssen Sie diese Basisklasse mithilfe der Kompilierungsweiterleitung neu kompilieren. Mit dieser Option wird sichergestellt, dass die abgeleiteten Klassen ebenfalls neu kompiliert werden. Um sicherzustellen, dass die abgeleiteten Klassen ebenfalls neu kompiliert werden, klicken Sie mit der rechten Maustaste auf den Basisklassenknoten, und klicken Sie dann auf Add-Ins > Weiterkompilieren. Die Alternative zum Klicken auf > Buildkompilierung (oder Drücken der F7-TASTE) reicht manchmal nicht aus, um eine Basisklassenänderung vorzunehmen. Eine Klasse kann null in viele Schnittstellen implementieren. Eine X++-Tabelle erbt implizit von der Common Tabelle und von der xRecord Klasse. |
C# verwendet das Erweiterungsstichwort , um von einer anderen Klasse abzuleiten. Alle .NET Framework-Klassen werden implizit von der System.Object Klasse abgeleitet, es sei denn, sie werden explizit von einer anderen Klasse abgeleitet. |
Stichwortvergleiche
In der folgenden Tabelle sind die OOP-bezogenen Schlüsselwörter in X++ und C# aufgeführt.
| Keyword | X++ | C# | Kommentare |
|---|---|---|---|
| abstract | Kein Unterschied. | ||
| Klasse | Die modifizierer öffentlich und privat werden für Klassendeklarationen ignoriert. Es gibt kein Konzept einer Namespacegruppierung von Klassen. Es gibt keine Punkte (.) in allen Klassennamen. | Die modifizierer öffentlich und privat können verwendet werden, um Klassendeklarationen zu ändern. C# verfügt auch über das interne Schlüsselwort, das sich auf die Gruppierung von Klassen in Assemblydateien bezieht. | Es gibt kein Konzept einer geschützten Klasse, nur geschützte Member einer Klasse. |
| Erweitert | Eine Klassendeklaration kann mithilfe des Schlüsselworts "erweitert " von einer anderen Klasse erben. | Ein Doppelpunkt (:) wird verwendet, in dem die Schlüsselwörter in X++ erweitert und implementiert werden. | |
| Finale | Eine endgültige Methode kann in einer abgeleiteten Klasse nicht überschrieben werden. Eine endgültige Klasse kann nicht erweitert werden. | Das schlüsselwort sealed on a class means the same thing that final means on an X++ class. | |
| Implementiert | Eine Klassendeklaration kann eine Schnittstelle mithilfe des implementierten Schlüsselworts implementieren. | ||
| interface | Eine Schnittstelle kann Methoden angeben, die die Klasse implementieren muss. | Eine Schnittstelle kann Methoden angeben, die die Klasse implementieren muss. | |
| Neu | Das neue Schlüsselwort wird verwendet, um eine neue Instanz einer Klasse zuzuweisen. Anschließend wird der Konstruktor automatisch aufgerufen. Jede Klasse verfügt über genau einen Konstruktor, und der Konstruktor wird benannt new. Sie können entscheiden, welche Parameter der Konstruktor eingeben soll. |
Das neue Schlüsselwort wird verwendet, um eine neue Instanz einer Klasse zu erstellen. Anschließend wird der Konstruktor automatisch aufgerufen. Konstruktormethoden selbst sind nicht benannt new, sie haben denselben Namen wie die Klasse.Anmerkung: Das neue Schlüsselwort kann auch für eine Methode verwendet werden, um die Art und Weise zu ändern, in der die Methode dieselbe Methode in der Basisklasse überschreibt. |
Sowohl X++ als auch C# setzen einen Standardkonstruktor für Klassen voraus, die keinen Konstruktor explizit in ihren Code geschrieben haben. |
| null | Kein Unterschied. | ||
| Privat und geschützt | Die privaten und geschützten Schlüsselwörter können verwendet werden, um die Deklaration eines Klassenelements zu ändern. | Die privaten und geschützten Schlüsselwörter können verwendet werden, um die Deklaration eines Klassenelements zu ändern. | |
| Öffentlich | Eine Methode, die nicht mit öffentlichen, geschützten oder privaten Personen geändert wird, verfügt über die Standardzugriffsstufe "Public". | Eine Methode, die nicht mit öffentlichen, geschützten oder privaten Personen geändert wird, verfügt über die Standardzugriffsstufe "Privat". | |
| statisch | Eine Methode kann statisch sein, aber ein Feld kann nicht. | Sowohl Methoden als auch Felder können statisch sein. | |
| super | Das Superschlüsselwort wird in einer abgeleiteten Klasse verwendet, um auf dieselbe Methode in der Basisklasse zuzugreifen. void method2(){ // Call method2 method // on the base class. super(); } |
Das Basisschlüsselwort wird in einer abgeleiteten Klasse verwendet, um auf verschiedene Methoden in der Basisklasse zuzugreifen. void method2() { // Call methods on // the base class. base.method2(); base.method3(); } |
In C# gibt es spezielle Syntax für die Verwendung der Basis , um den Basiskonstruktor aufzurufen. |
| das | Für einen Aufruf von einer Instanzmethode an eine andere für dasselbe Objekt ist ein Qualifizierer für die aufgerufene Methode erforderlich. Das Schlüsselwort , das als Qualifizierer für das aktuelle Objekt verfügbar ist. | Für einen Aufruf von einer Instanzmethode an eine andere für dasselbe Objekt ist kein Qualifizierer für die aufgerufene Methode erforderlich. Das Schlüsselwort ist jedoch als Qualifizierer für das aktuelle Objekt verfügbar. In der Praxis kann das Schlüsselwort hilfreich sein, indem IntelliSense-Informationen angezeigt werden. | |
finalize |
Die Object Klasse enthält die finalize Methode. Die finalize Methode ist nicht abgeschlossen und kann überschrieben werden. Die finalize Methode scheint der System.Object.Finalize Methode in C# ähnlich zu sein, aber in X++ hat die finalize Methode keine besondere Bedeutung. Ein Objekt wird automatisch aus dem Arbeitsspeicher entfernt, wenn der letzte Verweis auf das Objekt nicht mehr auf das Objekt verweist. Dies kann z. B. passieren, wenn der letzte Verweis außerhalb des Gültigkeitsbereichs liegt oder einem anderen Objekt zugewiesen ist, auf das verwiesen werden soll. |
Die Methoden Finalize und Dispose gelten für einige Klassentypen. Der Garbage Collector ruft die Finalize und Dispose methoden auf, wenn er zerstört und objekt. |
In C# kann die System.GC.Collect Methode im .NET Framework aufgerufen werden, um den Garbage Collector zu starten. In X++ gibt es keine ähnliche Funktion, da X++ einen deterministischen Garbage Collector verwendet. |
main |
Klassen, die aus einem Menü aufgerufen werden, haben ihre main Methode vom System aufgerufen. |
Klassen, die von einer Befehlszeilenkonsole aufgerufen werden, weisen die vom System aufgerufene Main Methode auf. |
Vergleich: Klassen
Wenn Sie C# im .NET Framework verwenden, werden Klassen in Namespaces gruppiert. Jeder Namespace konzentriert sich auf einen Funktionalen Bereich wie Dateivorgänge oder Spiegelung. Wenn Sie jedoch die Klassen in X++ verwenden, gibt es keine sichtbaren Gruppierungen wie einen Namespace.
Vergleich: Klassen über Spiegelung
In X++ bietet die TreeNode Klasse Zugriff auf die Application Object Tree (AOT). Die TreeNode Klasse ist das Zentrum der Spiegelungsfunktionalität in X++. Die TreeNode Klasse und die zugehörigen Methoden können mit dem System.Reflection Namespace in .NET Framework verglichen werden, den C# verwendet.
In der folgenden Tabelle sind mehrere Klassen aufgeführt, die Ihnen beim Schreiben von C#-Code zur Verfügung stehen. Dies sind .NET Framework-Klassen. Für diese Tabelle befinden sich alle C#-Klassen im System.Reflection Namespace, sofern nicht anders angegeben. Jede Zeile zeigt die entsprechende Klasse oder den entsprechenden Klassenmemmemm an, der Ihnen beim Schreiben von X++-Code zur Verfügung steht.
| X++ | C# | Kommentare |
|---|---|---|
TreeNode |
System .Assembly |
Assembly ist die erste Klasse, die verwendet werden soll, wenn ein C#-Programm Spiegelungsinformationen sammeln muss. Statische Methoden für die X++-Klasse TreeNode sind der Ausgangspunkt für die Spiegelung in X++. |
TreeNode |
System .Type |
Instanzmethoden entsprechen TreeNode Instanzenmethoden für System.Type. |
TreeNode .AOTgetSource |
MethodInfo |
Die AOTgetSource Methode gibt mehrere Informationselemente in einer Zeichenfolge zurück. Dazu gehört der X++-Quellcode in der Methode. Im Gegensatz dazu MethodInfo gibt es für jeden Informationsabschnitt ein separates Element. |
TreeNode .AOTfirstChild
TreeNode .AOTnextSibling
TreeNode .AOTiterator
AOTiterator
|
MethodInfo[] (ein Array) | In C# gibt die GetMethods Methode für System.Type ein Array von MethodInfo-Objekten zurück. Sie können das Array durchlaufen, indem Sie die gängige Technik zum Inkrementieren eines Indexers verwenden. Im Gegensatz dazu besteht das X++-Modell darin, im Struktursteuerelement des AOT zu navigieren. Die TreeNode Methoden und AOTfirstChildAOTnextSibling die Ausführung der Navigation. Als gleichwertige Alternative ist die X++ AOTiterator -Klasse so konzipiert, dass sie im Struktursteuerelement der AOT navigiert. Ein Klassenknoten ist das übergeordnete Element über mehrere Methodenknoten. Die AOTiterator Schritte durch untergeordnete Knoten, die jeweils als eine andere Instanz zurückgegeben werden TreeNode . Zusätzliche Ressourcen die Methoden, die TreeNode benannt AOTparent sind, und AOTprevious. |
TreeNode .AOTgetProperty
TreeNode .AOTgetProperties
TreeNode .AOTname
|
PropertyInfo |
In X++ gibt die AOTgetProperties Methode eine lange Zeichenfolge zurück, die Name-Wert-Paare für alle Eigenschaften der TreeNode. Die AOTname Methode gibt eine Zeichenfolge zurück, die nur den Wert für die Name-Eigenschaft enthält. |
TreeNode .AOTsave
TreeNode .AOTinsert
|
System .Reflection .Emit (Namespace von Klassen) |
Die AOTsave Methode wendet Änderungen von einem TreeNode Objekt in Ihrem X++-Code auf das AOT an, und die Änderungen werden beibehalten. Ein großes Codebeispiel finden Sie unter TreeNode.AOTsave-Methode. |
Vergleich: Klassen zu Datei-E/A
Es gibt mehrere Klassen, die Dateieingabe- und Ausgabevorgänge (IO) ausführen. In .NET Framework, das in C# verwendet wird, befinden sich die Gegenstücke zu diesen Klassen im System.IO Namespace.
In der folgenden Tabelle sind mehrere .NET Framework-Klassen für C# aufgeführt, die sich System.IO im Namespace befinden. Jede Zeile in der Tabelle zeigt die X++-Klasse oder -Methode, die der .NET Framework-Klasse am besten entspricht.
X++, ANSI SQL-Vergleich: SQL Select
In X++ unterscheidet sich die SQL Select-Anweisungssyntax von der Spezifikation des American National Standards Institute (ANSI).
Einzelne Tabelle auswählen
In der folgenden Tabelle sind unterschiede zwischen den Auswahlanweisungen von X++ SQL und ANSI SQL aufgeführt.
| Merkmal | X++ SQL | ANSI SQL | Kommentare |
|---|---|---|---|
| Tabellenname für die From-Klausel . | Die From-Klausel listet eine Datensatzpufferinstanz auf, die aus einer Tabelle deklariert wird, z. B. aus der CustTable Tabelle. |
In der From-Klausel wird ein Tabellenname und nicht der Name eines Puffers aufgeführt. | Der Datensatzpuffer verfügt über alle Methoden, die die xRecordKlasse in X++ hat. |
| Syntaxabfolge der Reihenfolge nach und nach klauseln . | Die Reihenfolge nach Klausel muss vor der Where-Klausel angezeigt werden. Die Reihenfolge nach Klausel muss nach der From - oder Join-Klausel angezeigt werden. Die Gruppierung nach Klausel muss den gleichen Syntaxpositionierungsregeln entsprechen, nach denen die Reihenfolge folgt. | Die Reihenfolge nach Klausel muss nach der Where-Klausel angezeigt werden. Die Where-Klausel muss nach der From - oder Join-Klausel angezeigt werden. | Sowohl in X++ als auch IN ANSI SQL müssen die From - und Join-Klauseln vor der Reihenfolge nach und wo Klauseln angezeigt werden. |
| Bedingungsver negation. | Das Ausrufezeichen ('!') wird für die Negation verwendet. | Das schlüsselwort not is used for negation. | X++ unterstützt die Syntax !like nicht. Stattdessen müssen Sie die ! operator to a clause. |
| Wildcardzeichen für den like-Operator . | 0 bis viele – Sternchen ('*') Genau 1 – Fragezeichen ('?') |
0 bis viele – Prozentzeichen ('%') Genau 1 – Unterleiste ('_') |
|
| Logische Operatoren in der Where-Klausel . | Und – && Oder – || |
Und – und Oder – oder |
Codebeispiel
Das folgende Codebeispiel veranschaulicht Features in der vorherigen Tabelle.
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
***/
X++-SQL-Schlüsselwörter
Die folgenden X++-SQL-Schlüsselwörter gehören zu denen, die nicht Teil von ANSI SQL sind:
- crosscompany
- firstonly100
- forceliterals
- forcenestedloop
- forceplaceholders
- forceselectorder
- validtimestate
Join-Klausel
In der folgenden Tabelle sind Unterschiede zum Join-Schlüsselwort von X++ SQL und ANSI SQL aufgeführt.
| Merkmal | X++ SQL | ANSI SQL | Kommentare |
|---|---|---|---|
| Spaltenliste. | Die Spalten in der Spaltenliste müssen alle aus der Tabelle stammen, die in der From-Klausel und nicht aus einer Tabelle in einer Verknüpfungsklausel aufgeführt ist. Spalten in der Liste können nicht durch ihren Tabellennamen qualifiziert werden. | Die Spalten in der Spaltenliste können aus einer beliebigen Tabelle in den Aus - oder Verknüpfungsklauseln stammen. Es hilft anderen, Ihren Code beizubehalten, wenn Sie die Spalten in der Liste mit ihrem Tabellennamen qualifizieren. | Weitere Informationen finden Sie unter Select Statements on Fields. |
| Syntax der Join-Klausel . | Die Verknüpfungsklausel folgt der Where-Klausel . | Die Verknüpfungsklausel folgt einer Tabelle in der From-Klausel . | Im X++-Codebeispiel ist die Verknüpfungskriterien eine Gleichheit von SalesPoolId Werten. |
| Inneres Schlüsselwort. | Der standardmäßige Verknüpfungsmodus ist die innere Verknüpfung. Es gibt kein inneres Schlüsselwort. | Der standardmäßige Verknüpfungsmodus ist die innere Verknüpfung. Das innere Schlüsselwort ist verfügbar, um den Code explizit zu machen. | Das äußere Schlüsselwort ist sowohl in X++ SQL als auch in ANSI SQL vorhanden. |
| Schlüsselwörter für links und rechts. | Die Schlüsselwörter links und rechts sind nicht verfügbar. Alle Verknüpfungen bleiben erhalten. | Die Schlüsselwörter links und rechts stehen zum Ändern des Verknüpfungsstichworts zur Verfügung. | Keine Kommentare. |
| Gleichheitsoperator. | Der Doppelten Gleichheitszeichenoperator ('==) wird verwendet, um die Gleichheit von zwei Werten zu testen. |
Der Single Equal Sign-Operator ('=' ) wird verwendet, um die Gleichheit von zwei Werten zu testen. |
Keine Kommentare. |
Codebeispiel
Im folgenden Codebeispiel wird die Verknüpfungssyntax in X++ SQL veranschaulicht.
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);
}
}
Aggregatfelder
In der folgenden Tabelle sind einige Unterschiede in der Art und Weise aufgeführt, wie Aggregatfelder in der Auswahlspaltenliste zwischen X++ SQL und ANSI SQL referenziert werden. Aggregatfelder sind diejenigen, die von Funktionen wie Summe oder Mittelwert abgeleitet werden.
| Merkmal | X++ SQL | ANSI SQL | Kommentare |
|---|---|---|---|
| Aggregieren des Feldnamenalias. | Der Aggregatwert befindet sich im Feld, das aggregiert wurde. | Sie können das Schlüsselwort verwenden, um ein Aggregatfeld mit einem Namensalias zu kennzeichnen. Auf den Alias kann im nachfolgenden Code verwiesen werden. | Weitere Informationen finden Sie unter "Aggregatfunktionen: Unterschiede zwischen X++ und SQL". |
Codebeispiel
Im folgenden Codebeispiel veranschaulicht der Aufruf der Info-Methode die Methode zum Verweisen auf Aggregatfelder (siehe tPurchLine.QtyOrdered).
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.
***/
Andere Unterschiede
In der folgenden Tabelle sind weitere Unterschiede der Select-Anweisung zwischen X++ SQL und ANSI SQL aufgeführt.
| Merkmal | X++ SQL | ANSI SQL | Kommentare |
|---|---|---|---|
| Das schlüsselwort . | Es gibt kein Stichwort. | Mit dem Schlüsselwort können Sie Filterkriterien für Zeilen angeben, die von der Gruppe nach Klausel generiert werden. | Keine Kommentare. |
| Null-Ergebnisse. | Wenn die Where-Klausel alle Zeilen herausfiltert, wird in einer While Select-Anweisung keine Spezielle Anzahlzeile zurückgegeben, um dies zu melden. | Wenn die Klausel in einer Auswahl alle Zeilen herausfiltert, wird eine spezielle Anzahl zeile zurückgegeben. Der Anzahlwert ist 0. | Keine Kommentare. |
| Cursor für die Navigation in zurückgegebenen Zeilen. | Die Select-Anweisung stellt Cursorfunktionen bereit. Die Alternative besteht darin, das nächste Schlüsselwort zu verwenden. | Sie können einen Cursor zum Durchlaufen der Zeilen deklarieren, die aus einer Select-Anweisung zurückgegeben werden. | |
| From-Klausel . | Das Schlüsselwort from ist optional, wenn keine Spalten aufgelistet werden und nur auf eine Tabelle verwiesen wird. Die folgenden beiden Syntaxoptionen sind gleichwertig: select \* from tCustTable; select tCustTable; |
Eine Select-Anweisung kann nicht aus einer Tabelle gelesen werden, es sei denn, die From-Klausel wird verwendet. | In X++ SQL füllt die einfache Select-Anweisung die Tabellenpuffervariable mit der ersten zurückgegebenen Zeile. Dies wird durch das folgende Codefragment veranschaulicht: select \* from tCustTable; info(tCustTable.Name); |