Nota
L'accesso a questa pagina richiede l'autorizzazione. Puoi provare ad accedere o a cambiare directory.
L'accesso a questa pagina richiede l'autorizzazione. Puoi provare a cambiare directory.
Nota
I gruppi di interesse della community sono ora passati da Yammer a Microsoft Viva Engage. Per entrare a far parte di una community Viva Engage e partecipare alle discussioni più recenti, compila il modulo Richiedi l'accesso alla community Viva Engage per Finance and Operations e scegli la community a cui vuoi unirti.
Questo articolo confronta la sintassi e la programmazione di X++ e C#.
Confronto tra X++ e C#: Hello World
In questa sezione viene confrontato il programma X++ più semplice con la sua controparte in C#.
Confronti tra X++ e C#
Nelle sezioni seguenti vengono descritte alcune analogie e differenze di base tra X++ e C#.
Somiglianze
Le funzionalità X++ seguenti sono le stesse per C#:
- Commenti a riga singola (
//) e a più righe (/* */). -
==(uguale) per determinare se due valori sono uguali. -
!=(diverso da) per determinare se due valori non sono equivalenti. -
+(segno più) per la concatenazione di stringhe.
Differenze
Nella tabella seguente sono elencate le funzionalità di X++ che sono diverse in C#.
| Caratteristica | X++ | C# | Commenti |
|---|---|---|---|
if e else istruzioni condizionali |
L'istruzione if accetta qualsiasi tipo di espressione che può convertire automaticamente in un valore booleano. Esempi comuni includono un per cui int 0 significa falso o un oggetto per cui null significa falso. |
L'istruzione if richiede un'espressione booleana. |
La struttura della sintassi relativa alle parentesi graffe e alle parentesi graffe è esattamente la stessa tra X++ e C#. |
| Stringa letterale | Una stringa letterale può essere delimitata utilizzando uno dei metodi seguenti:
|
Una stringa letterale deve essere delimitata da una coppia di virgolette doppie ("). | Per X++, le virgolette doppie vengono in genere utilizzate per delimitare le stringhe. Tuttavia, è conveniente delimitare una stringa con virgolette singole quando la stringa deve contenere un carattere di virgolette doppie. |
Char type |
Non esiste un tipo di carattere o un char in X++. Puoi dichiarare un str di lunghezza uno, ma è comunque una stringa:str 1 myString = "a"; |
C'è un char in C#. Non è possibile passare a char come parametro a a un metodo che immette un string parametro, anche se è possibile prima convertire in modo charesplicito .string |
Per ulteriori informazioni sui tipi di dati X++, vedere Tipi di dati primitivi. |
| Output dei messaggi | X++ recapita i messaggi all'utente nella finestra Infolog. I metodi comuni includono:
|
Per un programma a riga di comando, i messaggi possono essere recapitati alla console. I metodi comuni includono:
|
Esempi di X++ e C#
In questa sezione sono contenuti due semplici esempi di codice. Un esempio è scritto in X++ e l'altro è in C#. Entrambi i campioni ottengono lo stesso risultato. Vengono illustrate le seguenti funzionalità di X++:
-
//Commento a riga singola -
/\*\*/Commento su più righe -
ifaffermazione -
==operatore -
!=operatore -
+per concatenare le stringhe - Global::info per l'output del messaggio, con e senza il prefisso Global::
- Global::error per l'output del messaggio
- Utilizzo di virgolette singole e doppie (' e ") come delimitatori di stringa.
Nota
La procedura consigliata consiste nell'utilizzare le virgolette doppie per qualsiasi stringa che potrebbe essere visualizzata all'utente.
Esempio di X++
Questo esempio di codice X++ è sotto forma di processo. C'è un nodo chiamato Lavori nell'albero degli oggetti dell'applicazione (AOT). Questo esempio può essere aggiunto nel nodo Processi e quindi il processo può essere eseguito.
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
Di seguito è riportato l'output della finestra Infolog: Messaggio (09:49:48) Hello World, 1. Ciao mondo, 2. Questo è come info, ma è per gli avvertimenti, 3. Questo è come info, ma è per errori, 4.
Esempio di C#
Il seguente programma C# è una riscrittura del precedente programma X++.
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
Di seguito è riportato l'output effettivo nella console C#:
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.
Confronto tra X++ e C#: cicli
In questa sezione vengono confrontate le funzionalità del ciclo tra X++ e C#.
Somiglianze
Le funzionalità seguenti sono le stesse in X++ e C#:
- Dichiarazioni per variabili del tipo di dati int primitive. Le dichiarazioni per altri tipi primitivi sono quasi le stesse, ma i tipi potrebbero avere nomi diversi.
- while per i cicli.
- break per uscire da un ciclo.
- continue per passare all'inizio di un ciclo.
- <= (minore o uguale) operatore di confronto.
Differenze
Nella tabella seguente sono elencate le funzionalità di X++ che sono diverse in C#.
| Funzionalità | X++ | C# | Commenti |
|---|---|---|---|
L'affermazione for . |
L'istruzione for è disponibile per i cicli. | L'istruzione C# for è leggermente diversa da quella di for X++. |
In C# è possibile dichiarare il numero intero del contatore nell'istruzione for . Ma in X++ il contatore deve essere dichiarato all'esterno dell'istruzione for . |
| ++ Operatore di incremento. | In X++ è disponibile un operatore di incremento ++. Ma una variabile int decorata con ++ può essere utilizzata solo come istruzione, non come espressione. Ad esempio, le righe seguenti di codice X++ non vengono compilate:int age=42;print age++;Tuttavia, le seguenti righe di codice X++ verrebbero compilate: int age=42;age++; print age; |
L'operatore C#++ è più flessibile rispetto a X++. | Le righe di codice seguenti sono le stesse in entrambi i linguaggi:
|
| Operatore modulo. | In X++ l'operatore modulo è mod. | In C# l'operatore modulo è %. | I simboli per l'operatore modulo sono diversi, ma il loro comportamento è lo stesso in entrambi i linguaggi. |
| Sospendere temporaneamente un programma della console già avviato. | L'affermazione pause . |
In C# un programma della riga di comando può essere messo in pausa dalla riga di codice seguente:Console.In.Read(); |
In X++ si continua facendo clic su un pulsante OK in una finestra di dialogo modale. In C# si continua premendo una tastiera qualsiasi sulla tastiera. |
| Visualizzare un messaggio. | In X++, l'istruzione print visualizza un messaggio nella finestra Stampa. |
In C# è possibile visualizzare un messaggio nella console tramite la riga di codice seguente:Console.WriteLine(); |
La funzione X++ print viene utilizzata solo durante il test. Un programma X++ che utilizza print quasi sempre l'istruzione utilizza l'istruzione pause in un punto successivo del codice. Per il codice X++ di produzione, utilizzare il metodo Global::info anziché print. La strfmt funzione viene spesso utilizzata insieme a info. Non c'è motivo di usare pause dopo info. |
| Emetti un suono. | La funzione beep emette un suono che si può sentire. | In C# un suono che è possibile udire viene emesso dalla riga di codice seguente:Console.Beep(); |
Ciascuna delle affermazioni produce un tono breve. |
Stampa e globale::info
Gli esempi di codice X++ per i cicli usano la funzione per visualizzare i print risultati. In X++ è possibile utilizzare l'istruzione print in grado di visualizzare qualsiasi tipo di dati primitivo senza dover chiamare prima le funzioni che lo convertono in una stringa. Ciò è print utile in situazioni di test rapidi. Generalmente il metodo Global::info viene utilizzato più spesso di print. Il info metodo può visualizzare solo stringhe. Pertanto, la funzione strfmt viene spesso utilizzata insieme a info. Una limitazione di print è che non è possibile copiare il contenuto della finestra Stampa negli appunti (ad esempio con Ctrl+C). Global::info scrive nella finestra Infolog che supporta la copia negli appunti.
Esempio 1: Il ciclo while
La parola chiave while supporta il ciclo sia in X++ che in C#.
Esempio X++ di 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
L'output nella finestra Stampa X++ è il seguente:
1
2
3
4
Esempio C# di 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
L'output della console del programma C# è il seguente:
1
(Press any key to resume.)
2
(Press any key to resume.)
3
(Press any key to resume.)
4
(Press any key to resume.)
Esempio 2: il ciclo for
La parola chiave for supporta il ciclo sia in X++ che in C#.
Esempio X++ di for
In X++ la variabile contatore non può essere dichiarata come parte dell'istruzione for .
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
L'output nella finestra Stampa X++ è il seguente:
1
2
3
4
Esempio C# di for
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
L'output della console del programma C# è il seguente:
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.)
Confronto tra X++ e C#: Switch
Sia in X++ che in C#, l'istruzione switch include le parole chiave case, break e default. Nella tabella seguente sono elencate le differenze nell'istruzione switch tra X++ e C#.
| Caratteristica | X++ | C# | Commenti |
|---|---|---|---|
break; alla fine di ogni blocco di casi |
In X++, quando un blocco case corrisponde al valore dell'espressione nella clausola switch , tutti gli altri blocchi case e default vengono eseguiti fino a quando non viene raggiunta un'istruzione break; . In un'istruzione break; X++ non è mai necessaria alcuna istruzione, ma break; le istruzioni sono importanti in quasi tutte le situazioni pratiche. |
In C# è sempre necessaria un'istruzione break; dopo le istruzioni in un blocco case o predefinito . Se una clausola case non ha istruzioni tra se stessa e la clausola case successiva, non è necessaria un'istruzione break; tra le due clausole case . |
Si consiglia di non omettere l'istruzione break; dopo qualsiasi blocco di maiuscole e minuscole, perché può confondere il programmatore successivo che modifica il codice. |
break;alla fine del blocco predefinito |
In X++ non c'è un effetto dell'aggiunta di un'istruzione break; alla fine del blocco predefinito . |
In C# il compilatore richiede un'istruzione break; alla fine del blocco predefinito . |
Per ulteriori informazioni, vedere Istruzioni Switch. |
| Solo valori costanti su un blocco case | In X++ è possibile specificare un valore letterale o una variabile in un blocco case. Ad esempio, è possibile scrivere case myInteger:. | In C# è necessario specificare esattamente un valore letterale in ogni blocco case e non sono consentite variabili. | Nessun commento. |
| Valori multipli su un blocco di case | In X++ è possibile specificare più valori su ogni blocco di case. I valori devono essere separati da una virgola. Ad esempio, è possibile scrivere case 4,5,myInteger:. |
In C# è necessario specificare esattamente un valore per ogni blocco di case . | In X++ è meglio scrivere più valori su un blocco case piuttosto che omettere l'istruzione break; alla fine di uno o più blocchi case. |
Esempi di codice per switch
Nelle sezioni seguenti vengono illustrate istruzioni switch comparabili in X++ e C#.
Esempio di switch X++
Nell'esempio dell'opzione X++ viene illustrato quanto segue:
-
case iTemp:e per mostrare che le espressioni dicase (93-90):e minuscole non sono limitate alle costanti, come in C#. -
//break;per dimostrare chebreak;le istruzioni non sono necessarie in X++, anche se sono quasi sempre desiderabili. -
case 2, (93-90), 5:per mostrare che è possibile elencare più espressioni in una clausola case in X++.
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
***
Esempio di switch C#
Nell'esempio dell'opzione C# viene illustrato quanto segue:
- Caso 1: Contiene un commento che spiega che solo le espressioni costanti possono essere fornite su una clausola case .
-
break;Le istruzioni si verificano dopo l'ultima istruzione in ogni blocco case che contiene istruzioni, come richiesto da C#.
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
>>
***/
Confronto tra X++ e C#: maiuscole e minuscole e delimitatori
In questa sezione viene confrontato il trattamento delle stringhe con maiuscole e minuscole miste in X++ e C#. Vengono inoltre illustrati i delimitatori di stringa disponibili in X++.
Somiglianze
Le funzionalità di X++ seguenti sono identiche a quelle di C#:
- La barra rovesciata (\) è l'operatore di escape per i delimitatori di stringa.
- Il segno chiocciola (@) annulla l'effetto di escape della barra rovesciata quando il segno chiocciola viene scritto immediatamente prima delle virgolette aperte di una stringa.
- Il segno più (+) è l'operatore di concatenazione di stringhe.
Differenze
Le funzionalità di X++ diverse in C# sono elencate nella tabella seguente.
| Caratteristica | X++ | C# | Commenti |
|---|---|---|---|
== Operatore di confronto |
Insensibile: l'operatore è insensibile alle differenze nell'uso == delle stringhe. |
In C# l'operatore == è sensibile alle differenze tra maiuscole e minuscole delle stringhe. |
In X++ è possibile usare la funzione strCmp per confronti con distinzione tra maiuscole e minuscole tra stringhe. |
| Delimitatori di stringa | In X++ è possibile utilizzare le virgolette singole (') o doppie (") come delimitatore di stringa.Nota: In genere la procedura consigliata consiste nell'utilizzare le virgolette doppie per le stringhe che potrebbero essere visualizzate all'utente. Tuttavia, è conveniente delimitare una stringa con virgolette singole quando una virgoletta doppia è uno dei caratteri della stringa. |
In C# è necessario utilizzare le virgolette doppie come delimitatore di stringa. Si riferisce al tipo System.String. |
In X++ e C# è possibile incorporare un delimitatore in una stringa letterale ed eseguirne l'escape con . In X++ è inoltre possibile incorporare virgolette singole in una stringa delimitata da virgolette doppie (o viceversa), senza dover utilizzare l'escape. |
| Delimitatori di caratteri | X++ ha un tipo di dati stringa (str), ma nessun tipo di carattere. |
In C# è necessario utilizzare le virgolette singole come delimitatore di caratteri. Si riferisce al tipo System.Char. |
In .NET Framework, un System.String tipo di lunghezza uno è un tipo di dati diverso da un System.Char carattere. |
Esempio 1: Distinzione tra maiuscole e minuscole dell'operatore ==
Gli == operatori e != non fanno distinzione tra maiuscole e minuscole in X++, ma fanno distinzione tra maiuscole e minuscole in C#, come illustrato nell'esempio seguente.
| X++ | C# | Commenti |
|---|---|---|
"HELLO" == "hello" Vero in X++. |
"HELLO" == "hello" Falso in C#. |
Confronti tra maiuscole e minuscole diverse tra X++ e C#. |
Esempio 2: Operatore di concatenazione stringa +
Gli operatori + e += vengono utilizzati per concatenare stringhe sia in X++ che in C#, come illustrato dagli esempi nella tabella seguente.
| X++ | C# | Commenti |
|---|---|---|
myString1 = "Hello" + " world"; Il risultato è l'uguaglianza: myString1 == "Hello world" |
(Come per X++.) | Sia in X++ che in C#, il comportamento dell'operatore + dipende dal tipo di dati dei relativi operandi. L'operatore concatena stringhe o aggiunge numeri. |
mystring2 = "Hello"; myString2 += " world"; Il risultato è l'uguaglianza: myString2 == "Hello world" |
(Come per X++.) | Sia in X++ che in C# le istruzioni seguenti sono equivalenti: a = a + b; a += b; |
Esempio 3: Incorporamento ed escape dei delimitatori di stringa
È possibile utilizzare le virgolette singole o doppie per delimitare le stringhe in X++. Il carattere di escape (\) può essere utilizzato per incorporare delimitatori in una stringa. Questi sono illustrati nella tabella seguente.
| X++ | C# | Commenti |
|---|---|---|
myString1 = "They said \"yes\"."; Risultato: They said "yes". |
(Come per X++.) | Il carattere di escape consente di incorporare delimitatori di stringa all'interno delle stringhe. |
myString2 = 'They said "yes".'; Risultato: They said "yes". |
La sintassi C# non consente di delimitare le stringhe tra virgolette singole. | Per le stringhe che possono essere visualizzate dall'utente, è considerata una procedura consigliata usare il carattere di escape anziché le virgolette singole, come illustrato nell'esempio. |
myString3 = "They said 'yes'."; Risultato: They said 'yes'. |
(Come per X++.) | In X++, le virgolette singole non vengono considerate come delimitatori a meno che la stringa non inizi con un delimitatore di virgolette singole. In C# le virgolette singole non hanno un significato speciale per le stringhe e non possono essere utilizzate per delimitare le stringhe. In C# le virgolette singole sono il delimitatore obbligatorio per i valori letterali di tipo System.Char. X++ non dispone di alcun tipo di dati di tipo carattere. |
str myString4 = 'C'; In questo caso, la virgoletta singola è un delimitatore di stringa. |
char myChar4 = 'C'; In questo caso le virgolette singole sono un System.Char delimitatore, non un System.String delimitatore. |
X++ non dispone di alcun tipo di dati corrispondente a System.Char .NET Framework. Una stringa X++ limitata a una lunghezza di uno è comunque una stringa, non un tipo di dati di tipo carattere. |
Esempio 4: Carattere di escape singolo
Nella tabella seguente sono riportati esempi che illustrano il singolo carattere di escape nell'input o nell'output.
| X++ | C# | Commenti |
|---|---|---|
myString1 = "Red\ shoe"; Risultato: Red shoe |
Una stringa letterale in C# non può contenere la sequenza di due caratteri di escape seguita da uno spazio, ad esempio "\ ". Si verifica un errore del compilatore. | Quando il compilatore X++ rileva la sequenza di due caratteri di "\ ", elimina il singolo carattere di escape. |
myString2 = "Red\\ shoe"; Risultato: Red\ shoe |
(Come per X++.) | In una coppia di caratteri di escape, il primo nega il significato speciale del secondo. |
Confronto: sintassi degli array
Esistono somiglianze e differenze nelle funzionalità e nella sintassi per le matrici in X++ rispetto a C#.
Somiglianze
Nel complesso, c'è molta somiglianza nella sintassi e nel trattamento degli array in X++ e C#. Tuttavia, ci sono molte differenze.
Differenze
Nella tabella seguente sono elencate le aree della sintassi [] per le matrici diverse per X++ e C#.
| Categoria | X++ | C# | Commenti |
|---|---|---|---|
| Dichiarazione | Una matrice viene dichiarata con parentesi quadre aggiunte al nome della variabile. | Una matrice viene dichiarata con parentesi quadre aggiunte al tipo di dati. | int myInts[]; // X++ Nota: Una matrice X++ non può essere un parametro in un metodo.
|
| Dichiarazione | La sintassi della matrice supporta solo i tipi di dati primitivi, ad esempio int e str. La sintassi non supporta classi o tabelle. |
La sintassi della matrice supporta i tipi di dati e le classi primitive. | In X++ è possibile utilizzare l'array Array per un array di oggetti. |
| Dichiarazione | X++ è limitato a matrici a dimensione singola (myStrings[8]). | C# aggiunge il supporto per le matrici multidimensionali (myStrings[8,3]) e per le matrici frastagliate (myStrings[8][3]). | In X++ non è possibile avere una matrice di matrici. Tuttavia, esiste una sintassi avanzata per limitare la quantità di memoria attiva che una matrice di grandi dimensioni può utilizzare, che assomiglia alla sintassi multidimensionale in C#: int intArray[1024,16];. Per ulteriori informazioni, vedere Ottimizzazioni delle prestazioni delle procedure consigliate: scambio di array su disco. |
| Dichiarazione | In X++ un array è un costrutto speciale ma non è un oggetto. | In C# tutte le matrici sono oggetti, indipendentemente dalle variazioni di sintassi. | X++ dispone di una classe Array, ma il relativo meccanismo sottostante è diverso dalle matrici create utilizzando la sintassi []. In C# tutte le matrici utilizzano lo stesso meccanismo sottostante, indipendentemente dal fatto che nel System.Array codice venga utilizzata la sintassi [] della classe. |
| Lunghezza | In X++ la lunghezza di una matrice di dimensioni statiche è determinata nella sintassi della dichiarazione. | In C# la dimensione di una matrice viene determinata quando viene costruito l'oggetto matrice. | Quando si utilizza la sintassi di dichiarazione [] in X++, non sono necessarie ulteriori operazioni di preparazione prima di assegnare i valori alla matrice. In C# è necessario dichiarare e quindi costruire la matrice prima di assegnarla. |
| Lunghezza | Una matrice X++ può avere una lunghezza dinamica che può essere aumentata anche dopo l'inizio della popolazione. Ciò si applica solo quando l'array viene dichiarato senza un numero all'interno di []. Le prestazioni potrebbero essere rallentate se la lunghezza dell'array dinamico viene aumentata più volte. | In C# la lunghezza di una matrice non può essere modificata dopo che la lunghezza è stata impostata. | Nel frammento di codice X++ seguente solo la myInts matrice è dinamica e può aumentare di dimensioni. int myInts[]; int myBools[5]; myInts[2] = 12; myInts[3] = 13; myBools[6] = 26; //Error |
| Lunghezza | È possibile ottenere la lunghezza di alcuni array utilizzando la dimOf funzione. |
Le matrici C# sono oggetti che dispongono di una Length proprietà. |
Nessun commento. |
| Indicizzazione | L'indicizzazione degli array è in base 1. | L'indicizzazione degli array è in base 0. | mtIntArray[0] causerebbe un errore in X++. |
| Costante | In X++ un valore costante si ottiene in modo ottimale utilizzando la direttiva precompilatore #define . | In C# è possibile decorare la dichiarazione di variabile con la parola chiave const, per ottenere un valore costante. | X++ non ha una parola chiave const . C# non è in grado di assegnare valori alle variabili create dalla direttiva #define del precompilatore. |
Esempi di X++ e C#
Negli esempi di codice seguenti viene illustrata la gestione delle matrici di tipi di dati primitivi. Il primo esempio è in X++ e il secondo esempio è in C#. Entrambi i campioni ottengono gli stessi risultati.
Esempio di X++
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
L'output nell'Infolog è il seguente:
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
Esempio di C#
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
L'output del programma C# nella console della riga di comando è il seguente:
-------- 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]
Funzionalità X++ aggiuntive di tipo array
Il contenitore è un tipo di dati speciale disponibile in X++. Può essere considerato simile a una matrice o a una List raccolta.
Confronto: Collezioni
In un'applicazione per la finanza e le operazioni è possibile utilizzare la classe di raccolta X++ List . .NET Framework utilizzato in C# dispone di una classe simile denominata System.Collections.Generic.List.
Confronto dell'uso delle classi List
Nella tabella seguente vengono confrontati i metodi della classe X++ List con i metodi System.Collections.Generic.List di .NET Framework e C#.
| Caratteristica | X++ | C# | Commenti |
|---|---|---|---|
| Dichiarazione di raccolta | List myList; |
List<string> myList; |
La dichiarazione X++ non include il tipo di elementi da archiviare. |
| Dichiarazione dell'iteratore | ListIterator iterListEnumerator enumer; |
IEnumerator<stringa> iter; | In X++ l'oggetto ListIterator dispone di metodi che possono insert e delete di elementi Listda . X++ ListEnumerator non è in grado di modificare il contenuto di List. In X++ l'oggetto ListEnumerator viene sempre creato sullo stesso livello di List. Questo non è sempre vero per ListIterator. |
| Ottenere un iteratore | new ListIterator (myList)myList.getEnumerator() |
myList.GetEnumerator() |
Sia in X++ che in C# l'oggetto List dispone di un metodo getter per un enumeratore associato. |
| Costruttore | new List(Types::String) |
new List<string>() |
Le informazioni sul tipo di oggetti da archiviare all'interno delle List classi vengono fornite al costruttore sia in X++ che in C#. |
| Aggiornamento dei dati | Enumeratore: l'enumeratore non è valido se vengono aggiunti o rimossi elementi in .ListIteratore: l'iteratore dispone di metodi che inseriscono ed eliminano elementi da . List L'iteratore rimane valido. |
Enumeratore: l'enumeratore non è valido se vengono aggiunti o rimossi elementi in .List |
Gli enumeratori diventano non più validi dopo l'aggiunta o l'eliminazione Listdi elementi da , sia in X++ che in C#. |
| Aggiornamento dei dati | In X++ la List classe dispone di metodi per l'aggiunta di elementi all'inizio o alla fine dell'elenco. |
In C# la List classe dispone di metodi per l'aggiunta di membri in qualsiasi posizione nell'elenco. Dispone inoltre di metodi per rimuovere gli oggetti da qualsiasi posizione. |
In X++ gli elementi possono essere rimossi dal List solo da un iteratore. |
Esempio 1: Dichiarazione di un elenco
Gli esempi di codice seguenti sono in X++ e C# che dichiarano List insiemi.
// X++
List listStrings ,list2 ,listMerged;
ListIterator literator;
// C#
using System;
using System.Collections.Generic;
List<string> listStrings ,list2 ,listMerged; IEnumerator<string> literator;
Esempio 2: Costruzione di una lista
In entrambe le lingue, il tipo di articoli che la collezione memorizza deve essere specificato al momento della costruzione. Per i tipi di classe, X++ non può essere più specifico del fatto che il tipo sia una classe (Types::Class). Gli esempi di codice seguenti sono in X++ e C#.
// X++
listStrings = new List( Types::String );
// C#
listStrings = new List<string>;
Esempio 3: Aggiungere elementi a un elenco
Sia in X++ che in C# l'insieme fornisce un metodo per aggiungere un elemento alla fine dell'insieme e per inserire un elemento all'inizio. In C# l'insieme fornisce un metodo per l'inserimento in qualsiasi punto dell'insieme in base a un valore di indice. In X++, un iteratore di insiemi può inserire un elemento nella posizione corrente. Gli esempi di codice seguenti sono in X++ e C#.
// 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");
Esempio 4: Iterazione di un elenco
Sia X++ che C# dispongono di classi iteratore che è possibile utilizzare per scorrere gli elementi di un insieme un'istruzione alla volta, come illustrato negli esempi seguenti.
// 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);
}
Esempio 4b: foreach in C#
In C# la parola chiave foreach viene spesso utilizzata per semplificare l'attività di iterazione di un elenco. L'esempio di codice riportato di seguito si comporta in modo identico all'esempio di C# precedente.
foreach (string currentString in listStrings)
{
Console.WriteLine(currentString);
}
Esempio 5: Eliminazione del secondo elemento
Negli esempi di codice seguenti viene eliminato il secondo elemento dall'insieme. In X++ questo richiede un iteratore. In C# l'insieme stesso fornisce il metodo per la rimozione di un elemento.
// X++
literator.begin();
literator.next();
literator.delete();
// C#
listStrings.RemoveAt(1);
Esempio 6: Combinazione di due raccolte
Negli esempi di codice seguenti viene combinato il contenuto di due insiemi in uno solo.
// X++
listStrings = List::merge(listStrings ,listStr3);
// Or use the .appendList method:
listStrings.appendList (listStr3);
// C#
listStrings.InsertRange(listStrings.Count ,listStr3);
Confronto: raccolte di chiavi con valori
In un'applicazione per la finanza e le operazioni è possibile utilizzare la classe di Map raccolta. L'insieme Map contiene coppie di valori, il valore della chiave più un valore dei dati. È simile alla classe .NET Framework denominata System.Collections.Generic.Dictionary.
Somiglianze
Nell'elenco seguente vengono descritte le analogie tra X++ e C# per quanto riguarda le raccolte in cui vengono archiviate coppie chiave-valore:
- Entrambi impediscono la duplicazione delle chiavi.
- Entrambi utilizzano un enumeratore (o iteratore) per scorrere gli elementi.
- Entrambi gli oggetti dell'insieme chiave-valore vengono costruiti con le designazioni dei tipi archiviati come chiave e valore.
- Entrambi possono memorizzare oggetti classe e non sono limitati all'archiviazione di primitive come int.
Differenze
Nella tabella seguente vengono descritte le differenze tra X++ e C# per quanto riguarda le classi di insiemi in cui sono archiviate coppie chiave-valore:
| Caratteristica | X++ | C# | Commenti |
|---|---|---|---|
| Chiavi duplicate | In X++ la classe impedisce la Map duplicazione delle chiavi trattando in modo implicito la chiamata al relativo insert metodo come un'operazione per aggiornare solo il valore associato alla chiave. |
In C# la classe genera un'eccezione Dictionary quando si tenta di aggiungere una chiave duplicata. |
Le chiavi duplicate sono evitate in entrambe le lingue, anche se con tecniche diverse. |
| Elimina elementi | In X++ il delete metodo su un oggetto iteratore viene utilizzato per rimuovere una coppia chiave-valore indesiderata da un Mapoggetto . |
In C# la Dictionary classe dispone di un remove metodo. |
In entrambi i linguaggi, un enumeratore non è valido se il conteggio degli elementi dell'insieme viene modificato durante la durata dell'enumeratore. |
Esempio 1: Dichiarazione di una collezione Key-Value
In entrambe le lingue è necessario specificare il tipo di elementi archiviati nell'insieme chiave-valore. In X++ il tipo viene specificato al momento della costruzione. In C# il tipo viene specificato sia al momento della dichiarazione che al momento della costruzione. Gli esempi di codice seguenti sono in X++ e C#.
// X++
Map mapKeyValue;
MapEnumerator enumer;
MapIterator mapIter;
// C#
Dictionary<int,string> dictKeyValue;
IEnumerator<SysCollGen.KeyValuePair<int,string>> enumer;
KeyValuePair<int,string> kvpCurrentKeyValuePair;
Esempio 2: Costruzione della collezione
In entrambe le lingue, il tipo di elementi archiviati dall'insieme chiave-valore specificato durante la costruzione. Per i tipi di classe, X++ non può essere più specifico del fatto che il tipo sia una classe (Types::Class). Gli esempi di codice seguenti sono in X++ e C#.
// X++
mapKeyValue = new Map(Types::Integer, Types::String);
// C#
dictKeyValue = new Dictionary<int,string>();
Esempio 3: Aggiungere un elemento alla raccolta
Non esiste quasi alcuna differenza nel modo in cui un elemento viene aggiunto a un insieme chiave-valore in X++ e C#, come illustrato negli esempi di codice seguenti.
// X++
mapKeyValue.insert(xx ,int2str(xx) + “_Value”);
// C#
dictKeyValue.Add(xx ,xx.ToString() + “_Value”);
Esempio 4: Iterazione di una raccolta Key-Value
Gli enumeratori vengono utilizzati per eseguire il ciclo degli insiemi chiave-valore sia in X++ che in C#, come illustrato negli esempi di codice seguenti.
// 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.
}
Esempio 5: Aggiornamento del valore associato a una chiave
La sintassi è molto diversa tra i due linguaggi per un aggiornamento del valore associato a una determinata chiave. Gli esempi di codice seguenti sono per la chiave 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.”;
Esempio 6: Eliminazione di un elemento
La sintassi è molto diversa tra i due linguaggi per eliminare una coppia chiave-valore da un insieme, mentre si scorre l'iterazione tra i membri dell'insieme. Di seguito sono riportati esempi di codice per la chiave 102.
// 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);
Confronto: eccezioni
Esistono alcune somiglianze, ma molte differenze quando si confronta il comportamento correlato alle eccezioni tra X++ e C#. Le parole chiave try, catch e throw si comportano allo stesso modo in X++ e C#. Tuttavia, i tipi di eccezioni generate e intercettate sono diversi per le due lingue.
Somiglianze
Le analogie tra X++ e C# per quanto riguarda le funzionalità di eccezione includono gli esempi seguenti:
- Entrambe le lingue hanno la stessa parola chiave try .
- Entrambi hanno la stessa parola chiave catch .
- Entrambi abilitano un'istruzione catch che non specifica alcuna eccezione specifica. Tale istruzione catch rileva tutte le eccezioni che la raggiungono.
- Entrambi hanno la stessa parola chiave throw .
Differenze
Le differenze correlate alle eccezioni tra X++ e C# sono descritte nella tabella seguente.
| Caratteristica | X++ | C# | Commenti |
|---|---|---|---|
| ripetere | Passa alla prima istruzione nel blocco try associato. Per ulteriori informazioni, vedere Gestione delle eccezioni con le parole chiave try e catch. | La funzionalità della parola chiave retry può essere simulata nel codice C#, ma non esiste una parola chiave corrispondente. | Solo X++ ha una parola chiave retry . C# non ha una controparte. Per ulteriori informazioni, vedere Confronto tra X++ e C#: ripetizione automatica dei tentativi dopo un'eccezione. |
| finalmente | La finally parola chiave è supportata per seguire le try parole chiave and catch . |
La parola chiave finally contrassegna un blocco di codice che segue i blocchi try e catch . L'evento finally verrà eseguito indipendentemente dal fatto che venga generata o rilevata un'eccezione. | La semantica è identica a quella in C#. |
| Eccezioni specifiche | In X++ un'eccezione è un elemento dell'enumerazione Exception , ad esempio Error, Deadlock o CodeAccessSecurity. Nessuna eccezione può contenerne un'altra. |
In C# un'eccezione è un'istanza della System.Exception classe base o qualsiasi classe che eredita da essa. Un'eccezione può essere contenuta nella proprietà dell'eccezione InnerException generata. |
In X++ ogni eccezione generata è un valore dell'enumerazione Exception. Per ulteriori informazioni, vedere Enumerazione delle eccezioni. |
| Messaggio di eccezione | In X++ il messaggio che viene creato quando viene generata un'eccezione è disponibile solo nel registro informazioni e il messaggio non è direttamente collegato all'eccezione. | In C# il messaggio è il Message membro dell'oggetto System.Exception . |
In X++ il metodo Global::error è il meccanismo che visualizza i messaggi di eccezione nell'Infolog. Per ulteriori informazioni, vedere Gestione delle eccezioni con le parole chiave try e catch. |
| Condizioni di eccezione | In X++ si verifica un errore quando si chiama un metodo di istanza su una variabile oggetto a cui non è ancora stato assegnato alcun elemento. Tuttavia, non viene generata alcuna eccezione insieme a questo errore. Pertanto, nessun catch blocco può ottenere il controllo anche se la variabile non assegnata viene utilizzata in modo improprio in un try blocco. Nell'esempio di codice seguente, l'errore causato dal codice box4.toString(); non causa il trasferimento del controllo ad alcun catch blocco: DialogBox box4;try { box4.toString(); info("toString did not error, but expected an error."); } catch (Exception::Error) // Nessun valore di eccezione rileva questo.
info("Invalid use of box4 gave control to catch, unexpected."); { } |
In C# a System.NullReferenceException viene generato quando una variabile non inizializzata viene considerata come un riferimento a un oggetto. |
Potrebbero esserci molte altre differenze nelle condizioni che generano eccezioni. |
| Transazioni SQL | In X++, quando si verifica un'eccezione SQL in una transazione ttsBegin - ttsCommit , nessuna istruzione catch all'interno del blocco di transazione può elaborare l'eccezione. | In C# un blocco catch all'interno di una transazione SQL può rilevare l'eccezione. |
Esempi
Vengono illustrate le seguenti funzionalità di X++:
- Prova la parola chiave.
- catch parola chiave.
- Si verifica il comportamento dopo un'eccezione Exception::Error.
Esempio di X++
// 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
Di seguito è riportato l'output della finestra Infolog:
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.
Esempio di C#
Il seguente programma C# è una riscrittura del precedente programma X++.
// 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
Di seguito è riportato l'output per la console C#:
(e2) In catch block for -- System.IndexOutOfRangeException
'finally' is not an X++ keyword, although it's in C#.
End of program.
Confronto: Ripetizione automatica dei tentativi dopo un'eccezione
A volte è possibile scrivere codice in un blocco catch che corregge la causa di un'eccezione che si verifica durante la fase di esecuzione. X++ fornisce una parola chiave retry che può essere utilizzata solo all'interno di un blocco catch . La parola chiave retry consente a un programma di tornare all'inizio del blocco try dopo che il problema è stato corretto dal codice nel blocco catch . C# non dispone di una parola chiave retry . Tuttavia, il codice C# può essere scritto per fornire un comportamento equivalente.
Esempi di codice per la ripetizione dei tentativi
Il programma di esempio X++ seguente causa la generazione di un Exception::Error. Ciò si verifica quando tenta per la prima volta di leggere un elemento dalla sStrings matrice utilizzando un valore di indice non valido. Quando l'eccezione viene rilevata, viene intrapresa un'azione correttiva durante la fase di esecuzione all'interno del blocco catch . L'istruzione retry torna quindi alla prima istruzione nel blocco try . Questa seconda iterazione funziona senza incontrare alcuna eccezione.
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
Ecco l'output nella finestra Stampa:
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.
Esempio di C#
L'esempio C# seguente non è una traduzione riga per riga dell'esempio X++ precedente. Al contrario, il programma C# ha una struttura diversa in modo da simulare il comportamento della parola chiave retry su cui si basa il programma X++. I blocchi try e catch si trovano in un metodo chiamato. Le variabili utilizzate nel blocco try vengono archiviate nel metodo chiamante. Il metodo chiamante passa le variabili come parametri decorati con la parola chiave ref , in modo che i relativi valori possano essere corretti all'interno del blocco catch del metodo chiamato. Il metodo chiamato acquisisce tutte le eccezioni e restituisce un valore booleano per comunicare al chiamante se è necessaria una seconda chiamata.
// 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
Di seguito è riportato l'output per la console:
At top of try block: -1
In catch of -- Exception. Entering catch.
In catch of -- Exception. Leaving catch.
End of C# callee method.
At top of try block: 0
The array element is: First array element.
End of C# callee method.
End of C# caller method.
Confronto: operatori
In questa sezione vengono confrontati gli operatori tra X++ e C#.
Operatori di assegnazione
Nella tabella seguente vengono visualizzate le differenze tra gli operatori di assegnazione in X++ e C#.
| X++ e C# | Differenze |
|---|---|
= |
In X++ questo operatore causa una conversione implicita ogni volta che potrebbe verificarsi una perdita di precisione, ad esempio per un'assegnazione da int64 a int. Ma in C# l'assegnazione causa un errore di compilazione. |
+= e -= |
L'unica differenza è che in C# questi operatori vengono utilizzati anche nella modifica dei delegati. |
| ++ e -- | Questi sono gli operatori di incremento e decremento in entrambi i linguaggi. La seguente riga è identica in entrambe le lingue:++myInteger;Ma in X++ questi due operatori sono per le istruzioni, non per le espressioni. Pertanto, le righe seguenti generano errori di compilazione in X++: myStr = int2str(++myInteger);myIntA = myIntBB++; |
Operatori aritmetici
Nella tabella seguente sono elencati gli operatori aritmetici.
| X++ e C# | Differenze |
|---|---|
| * | Come operatore di moltiplicazione, non ci sono differenze. Nota: L'asterisco viene utilizzato anche nelle istruzioni SQL che fanno parte del linguaggio X++. In queste istruzioni SQL l'asterisco può anche essere uno dei seguenti:
|
/ |
L'operatore di divisione è lo stesso in X++ e C#. |
MOD |
Per le operazioni modulo, l'unica differenza è che il simbolo % viene utilizzato in C#. |
| + | L'operatore di addizione è lo stesso in X++ e C#. Il segno più viene utilizzato anche per la concatenazione di stringhe. Questo operatore aggiunge numeri e concatena stringhe in entrambe le lingue. |
| - | L'operatore di sottrazione è lo stesso in X++ e C#. |
Operatori bit per bit
Nella tabella seguente vengono confrontati gli operatori bit per bit tra X++ e C#.
| X++ e C# | Differenze |
|---|---|
| << | L'operatore di spostamento sinistro è lo stesso in X++ e C#. |
| >> | L'operatore di spostamento destro è lo stesso in X++ e C#. |
| ~ | L'operatore NOT bit per bit è lo stesso in X++ e C#. |
| & | L'operatore binario AND è lo stesso in X++ e C#. |
| ^ | L'operatore XOR binario è lo stesso in X++ e C#. |
Operatori relazionali
Gli operatori relazionali seguenti sono gli stessi in X++ e C#:
==<=<=><!=&&||!? :
Confronto: Eventi
Esistono alcune differenze nel modo in cui X++ e C# implementano il modello di progettazione degli eventi. Per ulteriori informazioni, vedere Terminologia e parole chiave degli eventi.
Confronto di eventi tra X++ e C#
Esistono differenze nel modo in cui i delegati vengono utilizzati per gli eventi in X++ rispetto a C#.
| Concetto | X++ | C# | Commenti |
|---|---|---|---|
| delegato | In X++, un delegato può essere dichiarato solo come membro di una classe. Un delegato non può essere un membro di una tabella. Tutti i delegati sono membri di istanza della classe, non membri statici . Non è possibile utilizzare alcun modificatore di accesso in una dichiarazione di delegato, poiché tutti i delegati sono membri protetti . Pertanto, l'evento può essere generato solo dal codice all'interno della stessa classe di cui il delegato è membro. Tuttavia, l'unica eccezione alla natura privata di un delegato è che il codice esterno alla classe può operare sui delegati utilizzando gli operatori += e -=. | In C# ogni delegato è un tipo, così come ogni classe è un tipo. Un delegato viene dichiarato indipendentemente da qualsiasi classe. Senza la parola chiave event , è possibile avere un delegato come tipo di parametro in un metodo, così come è possibile avere una classe come tipo di parametro. È possibile costruire un'istanza di un delegato da passare per il valore del parametro. | In X++, ogni classe è un tipo, ma nessun delegato è un tipo. Non è possibile costruire un'istanza di un delegato. Nessun delegato può essere un parametro per un metodo. Tuttavia, è possibile creare una classe che dispone di un membro delegato e passare istanze della classe come valori di parametro. Per altre informazioni, vedere Parole chiave X++. |
| evento | Nel codice X++, un evento è uno dei seguenti:
|
In C# la parola chiave event viene utilizzata per dichiarare un tipo delegato come membro di una classe. L'effetto della parola chiave event è quello di rendere il delegato protetto, ma comunque accessibile per gli operatori += e -=. È possibile sottoscrivere i metodi del gestore eventi a un evento utilizzando l'operatore +=. Un delegato può essere utile senza la parola chiave event , come tecnica per passare un puntatore a funzione come parametro in un metodo. | Gli eventi automatici che si verificano prima dell'inizio di un metodo e dopo la fine di un metodo possono essere sottoscritti solo utilizzando l'AOT. |
| Operatori += e -= | In X++ si usa l'operatore += per sottoscrivere i metodi a un delegato. L'operatore -= annulla la sottoscrizione di un metodo da un delegato. | In C# si usa l'operatore += per sottoscrivere i metodi a un evento o a un delegato che non viene usato con la parola chiave event . | Il delegato contiene un riferimento a tutti gli oggetti per i quali sono stati sottoscritti i metodi. Tali oggetti non sono idonei per l'operazione di Garbage Collection mentre il delegato contiene tali riferimenti. |
eventHandler |
In X++, la parola chiave eventHandler è obbligatoria quando si utilizza l'operatore += o -= per sottoscrivere o annullare la sottoscrizione di un metodo da un delegato. |
System.EventHandler è un tipo delegato in .NET Framework. |
Questo termine viene usato in modo diverso in X++ rispetto a C# o .NET Framework. Per altre informazioni, vedere Parole chiave X++. |
Esempio di X++
Nell'esempio X++ è necessario notare che è importante notare quanto segue:
Dispone
XppClassdi un membro delegato denominatomyDelegate.Nota
L'AOT contiene un nodo per il delegato. Il nodo si trova in AOT > Classes > XppClass > myDelegate. Diversi nodi del gestore eventi possono essere posizionati sotto il nodo myDedelegate. I gestori eventi rappresentati da nodi nell'AOT non possono essere rimossi dall'operatore -= durante la fase di esecuzione.
Le {} parentesi graffe alla fine della dichiarazione del delegato sono obbligatorie, ma non possono contenere codice.
Dispone
XppClassdi due metodi le cui firme dei parametri sono compatibili con il delegato. Un metodo è statico.I due metodi compatibili vengono aggiunti al delegato con l'operatore += e la parola chiave eventHandler . Queste istruzioni non chiamano i metodi del gestore eventi, ma aggiungono solo i metodi al delegato.
L'evento viene generato da una chiamata al delegato.
Il valore del parametro passato al delegato viene ricevuto da ogni metodo del gestore eventi.
Il breve processo X++ all'inizio dell'esempio avvia il 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);
}
}
L'output del precedente processo X++ è il seguente:
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.
Esempio di C#
In questa sezione è contenuto un esempio di codice C# per il modello di progettazione eventi dell'esempio X++ precedente.
// 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);
}
}
L'output dell'esempio C# precedente è il seguente:
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.
Gli eventi e l'AOT
Esistono altri sistemi di eventi che si applicano solo agli elementi dell'AOT. Per ulteriori informazioni, vedere Nodi del gestore eventi nell'AOT.
Confronto: Direttive del precompilatore
X++ e C# condividono alcune parole chiave per la sintassi della direttiva precompilatore, ma i significati non sono sempre gli stessi.
Somiglianze
I compilatori X++ e C# riconoscono molte delle stesse parole chiave. Nella maggior parte dei casi, le parole chiave hanno lo stesso significato per entrambi i compilatori di linguaggi.
Differenze
Una differenza fondamentale tra le direttive del precompilatore in X++ e C# è la parola chiave #define riconosciuta da entrambi i precompilatori del linguaggio. A differenza di C#, in X++ la direttiva #define richiede un punto nella sintassi. In X++, le parentesi possono essere utilizzate per assegnare un valore al simbolo definito. Queste differenze sono illustrate negli esempi seguenti:
- In X++: #define. Anno iniziale(2003)
- In C#: #define Anno Iniziale
Una differenza minore è che in C# possono essere presenti spazi e caratteri di tabulazione tra il carattere # e la parola chiave della direttiva, ad esempio # define Testing.
Parole chiave identiche
Nella tabella seguente sono elencate le direttive del precompilatore simili in X++ e C#.
| Parola chiave | X++ | C# | Commenti |
|---|---|---|---|
#define |
In X++ è possibile definire il nome di una variabile del precompilatore e assegnare un valore a tale variabile. | In C# è possibile definire il nome di una variabile del precompilatore, ma non è possibile assegnare alcun valore a tale variabile. Inoltre, qualsiasi #define in C# deve verificarsi all'inizio del file e non può verificarsi dopo alcun codice, ad esempio un'istruzione using o una dichiarazione di classe. | Il compilatore C# può immettere un parametro della riga di comando per definire il nome di /define una variabile del precompilatore senza definire la variabile in alcun file di codice C#. Il compilatore X++ non ha una controparte di /define. |
#if |
In X++, #if possibile determinare se esiste una variabile del precompilatore e se la variabile ha un determinato valore. | In C# #if possibile determinare solo se esiste una variabile del precompilatore. Non è possibile verificare la presenza di alcun valore perché non è possibile assegnare alcun valore. | |
#endif |
In X++, #endif segna la fine di un blocco #if. Termina anche un blocco #ifnot. | In C# #endif segna la fine di un blocco #if, indipendentemente dal fatto che il blocco includa o meno un #else. |
Parole chiave diverse con lo stesso risultato di elaborazione
Nella tabella seguente sono elencate le direttive del precompilatore denominate in modo diverso in X++ e C#, ma che restituiscono gli stessi risultati durante l'elaborazione.
| X++ | C# | Commenti |
|---|---|---|
| #ifnot | #if #else | Non esiste una direttiva #else in X++, ma il #ifnot fornisce funzionalità simili. In X++, #ifnot possibile determinare se esiste una variabile del precompilatore e se la variabile non ha un valore specifico specificato. In C# #if possibile determinare se esiste una variabile del precompilatore quando il '!' è preceduto dal nome della variabile. |
//BP Deviation documented |
#pragma avvertimento | Queste voci X++ e C# non sono equivalenti, ma esiste una somiglianza parziale. Entrambi eliminano i messaggi di avviso del compilatore. |
| #macrolib | . HPP file in C++ | Esiste una parziale somiglianza tra la direttiva X++ #macrolib e un . HPP file in C++. Entrambi possono contenere diverse istruzioni #define. |
Direttive del precompilatore esclusive di X++
Nella tabella seguente sono elencate le direttive del precompilatore X++ che non hanno una controparte diretta in C#.
| X++ | Commenti |
|---|---|
| #linenumber | La direttiva #linenumber serve per ottenere il numero di riga, in modo che possa essere inviato all'Infolog. La direttiva C# #line è diversa perché il suo scopo è l'impostazione del numero di riga. |
| #defdec #definc | |
| #globaldefine | In X++, c'è una piccola differenza tra #globaldefine e #define. La differenza consiste nel fatto che #globaldefine non sovrascrive mai un valore non nullo corrente assegnato a una variabile del precompilatore da #define. C# non ha nulla di simile a questa differenza, perché in C# non è possibile assegnare un valore al nome di una variabile del precompilatore. |
| #localmacro #macro | In X++, #localmacro consente di assegnare un valore multilinea a una variabile del precompilatore. #macro è un sinonimo, ma #localmacro è consigliato. In C# la direttiva #define dispone di parte di questa funzionalità, ma non è in grado di assegnare un valore a una variabile del precompilatore. |
| #globalmacro | In X++, #globalmacro è quasi uguale al #localmacro preferito. |
Confronto: Programmazione orientata agli oggetti
I principi di programmazione orientata agli oggetti (OOP) di X++ differiscono da C#.
Confronti concettuali
Nella tabella seguente viene confrontata l'implementazione dei principi OOP tra X++ e C#.
| Caratteristica | X++ | C# | Commenti |
|---|---|---|---|
| Colata | Il linguaggio X++ ha le parole chiave is e as, che vengono utilizzate per rendere sicuri ed espliciti i downcast. Suggerimento: X++ non richiede l'uso della parola chiave as quando si esegue il downcast di una variabile di classe base in una variabile di classe derivata. Tuttavia, è consigliabile che tutte le dichiarazioni negative utilizzino la parola chiave as . | È possibile eseguire il cast di un oggetto verso l'alto o verso il basso nel percorso di ereditarietà. I downcasts richiedono la parola chiave as . | Per ulteriori informazioni sulle parole chiave x++ is e as, vedere Operatori di espressione: is e as per l'ereditarietà. |
| Funzioni locali | Un metodo può contenere una dichiarazione e un corpo di codice per zero o più funzioni locali. Solo tale metodo può avere chiamate alla funzione locale. | C# 3.0 supporta le espressioni lambda, che presentano alcune somiglianze con le funzioni anonime e le funzioni locali. Le espressioni lambda vengono spesso utilizzate con i delegati. | |
| Overload dei metodi | L'overload dei metodi non è supportato. Il nome di un metodo può essere presente una sola volta per classe. | L'overload dei metodi è supportato. Il nome di un metodo può essere presente più volte in una classe, con firme di parametro diverse in ogni caso. | X++ supporta parametri facoltativi nei metodi. I parametri facoltativi possono simulare parzialmente l'overload del metodo. Per ulteriori informazioni, vedere la riga relativa ai parametri facoltativi in questa tabella. |
| Override del metodo | L'override del metodo è supportato. Una classe derivata può avere un metodo con lo stesso nome della classe base, purché la firma del parametro sia la stessa in entrambi i casi. L'unica eccezione è rappresentata dal fatto che il metodo di override può aggiungere un valore predefinito a un parametro. | L'override del metodo è supportato. La parola chiave virtual deve essere applicata a un metodo prima che il metodo possa essere sottoposto a override in una classe derivata. | Il concetto di override di un metodo include il nome del metodo, la firma del parametro e il tipo restituito. Il concetto di override del metodo non si applica se il metodo di base e il metodo di override differiscono in uno di questi aspetti. |
| Parametri facoltativi | Una dichiarazione di parametro può essere seguita da un'assegnazione di valore predefinita. Il chiamante del metodo ha la possibilità di passare un valore per tale parametro o di ignorare il parametro per accettare il valore predefinito. Questa funzionalità simula l'overload dei metodi perché due chiamate allo stesso nome di metodo possono passare un numero diverso di parametri. Ogni parametro che ha un valore predefinito deve seguire l'ultimo parametro che non ha un valore predefinito. | I parametri facoltativi sono supportati dalla parola chiave params . Anche senza la parola chiave params , dal punto di vista del chiamante, l'overload del metodo può fornire funzionalità parzialmente simili. | Per ulteriori informazioni, vedere Parametri e ambito e Utilizzo di parametri facoltativi. |
| Successione singola | È possibile derivare la classe X++ da un'altra classe X++ utilizzando la parola chiave extends nel nodo classDeclaration della classe, nell'AOT. Nessuna classe deriva in modo implicito direttamente da un'altra classe. Se si desidera che la Object classe derivi direttamente dalla classe, è necessario utilizzare la parola chiave extends . È possibile specificare una sola classe per la parola chiave extends .Attenzione: Quando si modifica una classe base X++ da cui derivano altre classi, è necessario ricompilare tale classe base utilizzando Compile forward. Questa opzione garantisce che anche le classi derivate vengano ricompilate. Per assicurarsi che vengano ricompilate anche le classi derivate, fare clic con il pulsante destro del mouse sul nodo della classe base e quindi scegliere Add-Ins > Compila in avanti. L'alternativa di fare clic su Compila > compilazione (o premere il tasto F7) è talvolta insufficiente per una modifica della classe base. Una classe può implementare zero a molte interfacce. Una tabella X++ eredita in modo implicito dalla Common tabella e dalla xRecord classe. |
C# utilizza la parola chiave extends per derivare da un'altra classe. Tutte le classi .NET Framework derivano in modo implicito dalla classe, a meno che non derivino in modo esplicito da un'altra System.Object classe. |
Confronti tra parole chiave
Nella tabella seguente sono elencate le parole chiave correlate a OOP in X++ e C#.
| Parola chiave | X++ | C# | Commenti |
|---|---|---|---|
| astratto | Nessuna differenza. | ||
| classe | I modificatori public e private vengono ignorati nelle dichiarazioni di classe. Non esiste il concetto di raggruppamento di classi nello spazio dei nomi. Non sono presenti punti (.) nei nomi delle classi. | I modificatori public e private possono essere utilizzati per modificare le dichiarazioni di classe. In C# è presente anche la parola chiave internal, che si riferisce al modo in cui le classi vengono raggruppate nei file di assembly. | Non esiste il concetto di classe protetta , ma solo membri protetti di una classe. |
| Si estende | Una dichiarazione di classe può ereditare da un'altra classe utilizzando la parola chiave extends . | I due punti (:) vengono utilizzati nel punto in cui le parole chiave si estendono e le implementa vengono utilizzate in X++. | |
| finale | Non è possibile eseguire l'override di un metodo finale in una classe derivata. Una lezione finale non può essere estesa. | La parola chiave sealed su una classe ha lo stesso significato che final significa su una classe X++. | |
| utensileria | Una dichiarazione di classe può implementare un'interfaccia utilizzando la parola chiave implements . | ||
| interfaccia | Un'interfaccia può specificare i metodi che la classe deve implementare. | Un'interfaccia può specificare i metodi che la classe deve implementare. | |
| Nuovo | La parola chiave new viene utilizzata per allocare una nuova istanza di una classe. Quindi il costruttore viene chiamato automaticamente. Ogni classe ha esattamente un costruttore e il costruttore è denominato new. È possibile decidere quali parametri deve essere inserito dal costruttore. |
La parola chiave new viene utilizzata per creare una nuova istanza di una classe. Quindi il costruttore viene chiamato automaticamente. I metodi costruttori stessi non sono denominati new, hanno lo stesso nome della classe.Nota: La parola chiave new può essere utilizzata anche in un metodo per modificare il modo in cui il metodo esegue l'override dello stesso metodo nella classe base. |
Sia X++ che C# presuppongono un costruttore predefinito per le classi che non hanno alcun costruttore scritto in modo esplicito nel codice. |
| nullo | Nessuna differenza. | ||
| privato e protetto | Le parole chiave private e protette possono essere utilizzate per modificare la dichiarazione di un membro della classe. | Le parole chiave private e protette possono essere utilizzate per modificare la dichiarazione di un membro della classe. | |
| pubblico | Un metodo che non viene modificato con public, protected o private ha il livello di accesso predefinito public. | Un metodo che non viene modificato con public, protected o private ha il livello di accesso predefinito private. | |
| statico | Un metodo può essere statico, ma un campo no. | Sia i metodi che i campi possono essere statici. | |
| super | La parola chiave super viene utilizzata in una classe derivata per accedere allo stesso metodo nella relativa classe base. void method2(){ // Call method2 method // on the base class. super(); } |
La parola chiave base viene utilizzata in una classe derivata per accedere a vari metodi nella relativa classe base. void method2() { // Call methods on // the base class. base.method2(); base.method3(); } |
In C# è disponibile una sintassi speciale per l'uso di base per chiamare il costruttore di base. |
| questo | Per una chiamata da un metodo di istanza a un altro sullo stesso oggetto, è necessario un qualificatore per il metodo chiamato. La parola chiave this è disponibile come qualificatore per l'oggetto corrente. | Per una chiamata da un metodo di istanza a un altro sullo stesso oggetto, non è necessario un qualificatore per il metodo chiamato. Tuttavia, la parola chiave this è disponibile come qualificatore per l'oggetto corrente. In pratica, la parola chiave this può essere utile visualizzando le informazioni di IntelliSense. | |
finalize |
La Object classe contiene il finalize metodo. Il finalize metodo non è definitivo e può essere sovrascritto. Il finalize metodo sembra assomigliare System.Object.Finalize al metodo in C#, ma in X++ il finalize metodo non ha alcun significato speciale di alcun tipo. Un oggetto viene rimosso automaticamente dalla memoria quando l'ultimo riferimento all'oggetto smette di fare riferimento all'oggetto. Ad esempio, ciò può verificarsi quando l'ultimo riferimento esce dall'ambito o viene assegnato un altro oggetto a cui fare riferimento. |
I metodi Finalize e Dispose sono comuni ad alcuni tipi di classi. Il Garbage Collector chiama i metodi and Finalize quando elimina l'oggetto Dispose and. |
In C# è possibile chiamare il System.GC.Collect metodo in .NET Framework per avviare il Garbage Collector. Non esiste una funzione simile in X++ perché X++ utilizza un garbage collector deterministico. |
main |
Il metodo delle classi richiamate da un menu viene main chiamato dal sistema. |
Il metodo Main delle classi richiamate da una console della riga di comando viene chiamato dal sistema. |
Confronto: Classi
Quando si utilizza C# in .NET Framework, le classi vengono raggruppate in spazi dei nomi. Ogni spazio dei nomi è incentrato su un'area funzionale, ad esempio le operazioni sui file o la reflection. Tuttavia, quando si utilizzano le classi in X++, non sono presenti raggruppamenti visibili come uno spazio dei nomi.
Confronto: Lezioni sulla Riflessione
In X++ la classe fornisce l'accesso TreeNode all'Application Object Tree (AOT). La TreeNode classe è il centro della funzionalità di reflection in X++. La TreeNode classe e i relativi metodi possono essere confrontati con lo System.Reflection spazio dei nomi in .NET Framework utilizzato da C#.
Nella tabella seguente sono elencate diverse classi disponibili per la scrittura di codice C#. Si tratta di classi .NET Framework. Per questa tabella, tutte le classi C# si trovano nello spazio dei System.Reflection nomi, se non diversamente specificato. Ogni riga mostra la classe corrispondente, o membro della classe, disponibile per la scrittura di codice X++.
| X++ | C# | Commenti |
|---|---|---|
TreeNode |
System .Assembly |
Assembly è la prima classe da utilizzare quando un programma C# deve raccogliere informazioni di reflection. I metodi statici nella classe TreeNode X++ sono il punto di partenza per la reflection in X++. |
TreeNode |
System .Type |
I metodi di istanza on TreeNode corrispondono ai metodi di istanza on System.Type. |
TreeNode .AOTgetSource |
MethodInfo |
Il AOTgetSource metodo restituisce diverse informazioni in un'unica stringa. Ciò include il codice sorgente X++ nel metodo. Al contrario, MethodInfo ha un membro separato per ogni informazione. |
TreeNode .AOTfirstChild
TreeNode .AOTnextSibling
TreeNode .AOTiterator
AOTiterator
|
MethodInfo[] (un array) | In C# il GetMethods metodo on System.Type restituisce una matrice di oggetti MethodInfo. È possibile eseguire il ciclo della matrice con la tecnica comune di incremento di un indicizzatore. Al contrario, il modello X++ consiste nello spostamento nel controllo albero dell'AOT. I TreeNode metodi di AOTfirstChild e AOTnextSibling realizzare la navigazione. Come alternativa equivalente, la classe X++ AOTiterator è progettata per spostarsi nel controllo albero dell'AOT. Un nodo di classe è l'elemento padre di diversi nodi del metodo. I AOTiterator passaggi da un nodo figlio all'altro, restituendo ciascuno come un'altra TreeNode istanza. Risorse aggiuntive, i TreeNode metodi denominati AOTparent e AOTprevious. |
TreeNode .AOTgetProperty
TreeNode .AOTgetProperties
TreeNode .AOTname
|
PropertyInfo |
In X++, il AOTgetProperties metodo restituisce una stringa lunga che contiene coppie nome-valore per tutte le proprietà di TreeNode. Il AOTname metodo restituisce una stringa che contiene solo il valore per la proprietà name. |
TreeNode .AOTsave
TreeNode .AOTinsert
|
System .Reflection .Emit (namespace delle classi) |
Il AOTsave metodo applica le modifiche da un TreeNode oggetto nel codice X++ all'AOT e le modifiche vengono mantenute. Per un esempio di codice di grandi dimensioni, vedere Metodo TreeNode.AOTsave. |
Confronto: Classi su File IO
Esistono diverse classi che eseguono operazioni di input e output di file (IO). In .NET Framework utilizzato in C#, le controparti di queste classi risiedono nello spazio dei System.IO nomi.
Nella tabella seguente sono elencate diverse classi .NET Framework per C# che si trovano nello spazio dei System.IO nomi. Ogni riga della tabella mostra la classe o il metodo X++ che corrisponde meglio alla classe .NET Framework.
| X++ | C# | Commenti |
|---|---|---|
BinaryIo |
FileStream
BinaryReader
BinaryWriter
|
Le classi X++ come BinaryIo quelle che si estendono dalla classe Io astratta fungono da flusso e fungono anche da lettore e scrittore per tale flusso. In C# il flusso è una classe separata dalla classe che dispone di metodi di lettura e scrittura più specifici. |
TextBuffer |
MemoryStream |
Queste classi contengono un buffer in memoria e alcuni metodi trattano il buffer come se fosse un file sul disco rigido. |
| WINAPI::createDirectory WINAPI::folderExists WINAPI::removeDirectory |
Directory
DirectoryInfo
Path
|
X++ può utilizzare metodi statici nella classe per molte funzioni di base del WINAPI sistema operativo che coinvolgono directory. |
| WINAPI::getDriveType |
DriveInfo
DriveType
|
Queste classi e metodi vengono utilizzati per ottenere informazioni relative all'unità. |
| WINAPI::copyFile WINAPI::createFile WINAPI::d eleteFile WINAPI::fileExists |
File
FileAttributes
FileInfo
|
X++ può utilizzare metodi statici nella classe per molte funzioni di base del WINAPI sistema operativo che coinvolgono i file. |
CommaIo
Comma7Io
|
(Nessuna classe corrispondente.) | Queste classi X++ possono generare file che possono essere importati da Microsoft Excel. In X++ è disponibile un riferimento alla libreria EPPlus per un'ulteriore interazione con Excel. |
AsciiIo
TextIo
|
FileStream
TextReader
TextWriter
|
Queste classi utilizzano tabelle codici diverse. |
Io |
Stream
StreamReader
StreamWriter
FileStream
|
Queste vengono spesso utilizzate come classi di base estese da altre classi. |
CodeAccessPermission
FileIoPermission
|
System.Security
.CodeAccessPermission Lo spazio dei System.Security.Permissions nomi include le classi seguenti:
|
I concetti e i metodi di assert, demand, e revertAssert si applicano a entrambi i linguaggi. Tuttavia, i deny metodi e revertDeny disponibili in C# non sono disponibili in X++. |
Confronto SQL X++, ANSI: selezione SQL
In X++, la sintassi dell'istruzione SQL select è diversa dalla specifica ANSI (American National Standards Institute).
Selezione tavolo singolo
Nella tabella seguente sono elencate le differenze tra le istruzioni select di X++ SQL e ANSI SQL.
| Caratteristica | X++ SQL | ANSI SQL | Commenti |
|---|---|---|---|
| Nome della tabella nella clausola from . | La clausola from elenca un'istanza del buffer di record dichiarata da una tabella, ad esempio dalla CustTable tabella. |
La clausola from elenca il nome di una tabella, non il nome di un buffer. | Il buffer dei record include tutti i metodi che la xRecordclasse ha in X++. |
| Sequenza di sintassi delle clausole order by versus where . | La clausola order by deve apparire prima della clausola where . La clausola order by deve essere visualizzata dopo la clausola from o join . La clausola group by deve seguire le stesse regole di posizionamento della sintassi seguite dall'order by. | La clausola order by deve apparire dopo la clausola where . La clausola where deve essere visualizzata dopo la clausola from o join . | Sia in X++ che in ANSI SQL, le clausole from e join devono essere visualizzate prima delle clausole order by e where . |
| Negazione della condizione. | Il punto esclamativo ('!') viene utilizzato per la negazione. | La parola chiave not viene utilizzata per la negazione. | X++ non supporta la sintassi !like. È invece necessario applicare il metodo ! a una clausola. |
| Caratteri jolly per l'operatore simile . | Da 0 a molti – Asterisco ('*') Esattamente 1 – Punto interrogativo ('?') |
Da 0 a molti – Segno di percentuale ('%') Esattamente 1 – Sottobarra ('_') |
|
| Operatori logici nella clausola where . | E – && Oppure – || |
E – e Oppure – o |
Esempio di codice
Nell'esempio di codice riportato di seguito vengono illustrate le funzionalità della tabella precedente.
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
***/
Parole chiave X++ SQL
Le parole chiave X++ SQL seguenti sono tra quelle che non fanno parte di ANSI SQL:
- interaziendale
- firstonly100
- valori letterali forzati
- forcenestedloop
- forcesegnaposto
- forceselectorder
- validtimestato
Clausola di join
Nella tabella seguente sono elencate le differenze relative alla parola chiave join di X++ SQL e ANSI SQL.
| Caratteristica | X++ SQL | ANSI SQL | Commenti |
|---|---|---|---|
| Elenco colonne. | Le colonne nell'elenco delle colonne devono provenire tutte dalla tabella elencata nella clausola from e non da alcuna tabella in una clausola join . Le colonne nell'elenco non possono essere qualificate in base al nome della tabella. | Le colonne nell'elenco delle colonne possono provenire da qualsiasi tabella nelle clausole from o join . Aiuta gli altri utenti a gestire il codice quando si qualificano le colonne nell'elenco con il nome della tabella. | Per ulteriori informazioni, vedere Selezione di istruzioni per i campi. |
| Sintassi della clausola di join . | La clausola join segue la clausola where . | La clausola join segue una tabella nella clausola from . | Nell'esempio di codice X++, il criterio di join è un'uguaglianza di SalesPoolId valori. |
| Parola chiave interna . | La modalità di join predefinita è l'inner join. Non esiste una parola chiave interna . | La modalità di join predefinita è l'inner join. La parola chiave inner è disponibile per rendere esplicito il codice. | La parola chiave outer esiste sia in X++ SQL che in ANSI SQL. |
| Parole chiave sinistra e destra . | Le parole chiave sinistra e destra non sono disponibili. Tutti i join vengono lasciati. | Le parole chiave sinistra e destra sono disponibili per modificare la parola chiave join . | Nessun commento. |
| Operatore di uguaglianza. | L'operatore del doppio segno di uguale ('==') viene utilizzato per verificare l'uguaglianza di due valori. |
L'operatore del segno di uguale singolo ('=') viene utilizzato per verificare l'uguaglianza di due valori. |
Nessun commento. |
Esempio di codice
Nell'esempio di codice riportato di seguito viene illustrata la sintassi di join in X++ SQL.
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);
}
}
Campi aggregati
Nella tabella seguente sono elencate alcune differenze nel modo in cui viene fatto riferimento ai campi aggregati nell'elenco delle colonne di selezione tra X++ SQL e ANSI SQL. I campi aggregati sono quelli derivati da funzioni quali somma o media.
| Caratteristica | X++ SQL | ANSI SQL | Commenti |
|---|---|---|---|
| Alias del nome del campo aggregato. | Il valore aggregato si trova nel campo che è stato aggregato. | È possibile utilizzare la parola chiave as per contrassegnare un campo aggregato con un alias di nome. È possibile fare riferimento all'alias nel codice successivo. | Per ulteriori informazioni, vedere Funzioni di aggregazione: differenze tra X++ e SQL |
Esempio di codice
Nell'esempio di codice seguente, la chiamata al metodo info illustra il modo per fare riferimento ai campi di aggregazione (vedere 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.
***/
Altre differenze
Nella tabella seguente sono elencate altre differenze dell'istruzione select tra SQL X++ e SQL ANSI.
| Caratteristica | X++ SQL | ANSI SQL | Commenti |
|---|---|---|---|
| La parola chiave avere . | Non esiste una parola chiave having . | La parola chiave having consente di specificare i criteri di filtro per le righe generate dalla clausola group by. | Nessun commento. |
| Risultati nulli. | In un'istruzione while select, se la clausola where filtra tutte le righe, non viene restituita alcuna riga di conteggio speciale per segnalarlo. | In una clausola select, se la clausola where filtra tutte le righe, viene restituita una riga di conteggio speciale. Il valore del conteggio è 0. | Nessun commento. |
| Cursori per lo spostamento tra le righe restituite. | L'istruzione while select fornisce la funzionalità del cursore. L'alternativa è utilizzare la parola chiave successiva . | È possibile dichiarare un cursore per scorrere le righe restituite da un'istruzione select . | |
| Dalla clausola. | La parola chiave from è facoltativa quando non sono elencate colonne e viene fatto riferimento a una sola tabella. Le due opzioni di sintassi seguenti sono equivalenti: select \* from tCustTable; select tCustTable; |
Un'istruzione select non può leggere da una tabella a meno che non venga utilizzata la clausola from . | In X++ SQL, l'istruzione select semplice riempie la variabile del buffer della tabella con la prima riga restituita. Ciò è illustrato dal frammento di codice seguente: select \* from tCustTable; info(tCustTable.Name); |