Partilhar via


Comparação entre X++ e C#

Observação

Os grupos de interesse da comunidade passaram do Yammer para o Microsoft Viva Engage. Para participar de uma comunidade Viva Engage e participar das últimas discussões, preencha o formulário Solicitar acesso ao Finance and Operations Viva Engage Community e escolha a comunidade à qual deseja participar.

Este artigo compara a sintaxe e a programação de X++ e C#.

Comparação X++, C#: Hello World

Esta seção compara o programa X++ mais simples com seu homólogo em C#.

Comparações X++ com C#

As seções a seguir descrevem algumas semelhanças e diferenças básicas entre X++ e C#.

Semelhanças

Os seguintes recursos do X++ são os mesmos para C#:

  • Comentários de linha única (//) e de várias linhas (/* */).
  • == operador (igual) para determinar se dois valores são iguais.
  • != (não igual a) operador para determinar se dois valores não são equivalentes.
  • + (sinal de adição) para concatenação de cadeia de caracteres.

Diferenças

A tabela a seguir lista os recursos X++ que são diferentes em C#.

Característica X++ C# Comments
if e else declarações condicionais A if instrução aceita qualquer tipo de expressão que possa converter automaticamente em booleana. Exemplos comuns incluem um int para o qual 0 significa falso ou um objeto para o qual null significa falso. A if instrução requer uma expressão booleana. A estrutura de sintaxe em relação a chaves e parênteses é exatamente a mesma entre X++ e C#.
Cadeia literal Uma cadeia de caracteres literal pode ser delimitada usando um dos seguintes métodos:
  • Um par de aspas duplas (") caracteres.
  • Um par de aspas simples (').
Uma cadeia de caracteres literal deve ser delimitada por um par de aspas duplas (") caracteres. Para X++, os caracteres de aspas duplas geralmente são usados para delimitar cadeias de caracteres. No entanto, é conveniente delimitar uma cadeia de caracteres com aspas simples quando a cadeia de caracteres deve conter um caractere de aspas duplas.
Char type Não há um char ou um tipo de caractere no X++. Você pode declarar um str de comprimento um, mas ainda é uma cadeia de caracteres:
str 1 myString = "a";
Há um char em C#. Você não pode passar um char como o parâmetro para um método que insere um string parâmetro, embora você possa primeiro converter explicitamente o char para um string. Para obter mais informações sobre tipos de dados X++, consulte Tipos de dados primitivos.
Saída de mensagens X++ entrega mensagens ao usuário na janela Infolog. Os métodos comuns incluem:
  • A declaração impressa :
  • Métodos estáticos na Global classe:
    • Global::info
    • Global::aviso
    • Global::erro
Para um programa de linha de comando, as mensagens podem ser entregues ao console. Os métodos comuns incluem:
  • Console.Out.WriteLine
  • Console.Error.WriteLine

Exemplos de X++ e C#

Esta seção contém dois exemplos de código simples. Um exemplo é escrito em X++ e o outro está em C#. Ambas as amostras obtêm o mesmo resultado. Os seguintes recursos X++ são demonstrados:

  • // comentário de linha única
  • /\* \*/ comentário de várias linhas
  • Declaração if
  • == Operador
  • != Operador
  • + operador para concatenar cadeias de caracteres
  • Global::info para saída de mensagem, com e sem o prefixo Global::
  • Global::erro para saída de mensagem
  • O uso de aspas simples e duplas (' e ") como delimitadores de string.

Observação

A prática recomendada é usar aspas duplas para qualquer cadeia de caracteres que possa ser exibida para o usuário.

Exemplo de X++

Este exemplo de código X++ está na forma de um trabalho. Há um nó intitulado Jobs na Application Object Tree (AOT). Este exemplo pode ser adicionado no nó Trabalhos e, em seguida, o trabalho pode ser executado.

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

Aqui está a saída da janela Infolog: Mensagem (09:49:48) Olá Mundo, 1. Olá Mundo, 2. Isto é como informação, mas é para avisos, 3. Isto é como informação, mas é para erros, 4.

Exemplo de C#

O seguinte programa C# é uma reescrita do programa X++ anterior.

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

Aqui está a saída real para o 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.

Comparação X++, C#: Loops

Esta seção compara os recursos de loop entre X++ e C#.

Semelhanças

Os seguintes recursos são os mesmos em X++ e C#:

  • Declarações para variáveis do tipo de dados primitivo int. As declarações para outros tipos primitivos são quase as mesmas, mas os tipos podem ter nomes diferentes.
  • enquanto instrução para loops.
  • quebrar instrução para sair de um loop.
  • Continue a declaração para saltar para o topo de um loop.
  • <= (menor ou igual) operador de comparação.

Diferenças

A tabela a seguir lista os recursos X++ que são diferentes em C#.

Caraterísticas X++ C# Comments
A for declaração. A instrução for está disponível para loops. A instrução C# for é ligeiramente diferente da for instrução X++. Em C#, você pode declarar o número inteiro do for contador na instrução. Mas em X++ o contador deve ser declarado fora da for instrução.
++ operador de incremento. Um operador de incremento ++ está disponível no X++. Mas uma variável int que é decorada com ++ só pode ser usada como uma declaração, não como uma expressão. Por exemplo, as seguintes linhas de código X++ não seriam compiladas:
int age=42;
print age++;
No entanto, as seguintes linhas de código X++ seriam compiladas:
int age=42;
age++; print age;
O operador C# ++ é mais flexível do que no X++. As seguintes linhas de código são as mesmas em ambos os idiomas:
  • ++ myInteger;
  • myInteger++;
Mas as seguintes linhas de código têm um efeito diferente umas das outras e são válidas apenas em C#:
  • yourInt = ++myInt;
  • yourInt = myInt++;
operador de módulo. Em X++ o operador modulo é mod. Em C# o operador modulo é %. Os símbolos para o operador de módulo são diferentes, mas seu comportamento é o mesmo em ambas as línguas.
Suspenda temporariamente um programa de console que já tenha começado. A pause declaração. Em C#, um programa de linha de comando pode ser pausado pela seguinte linha de código:
Console.In.Read();
No X++, você continua clicando em um botão OK em uma caixa de diálogo modal. Em C#, você continua pressionando qualquer teclado no teclado.
Exiba uma mensagem. No X++, a print instrução exibe uma mensagem na janela Imprimir. Em C#, uma mensagem pode ser exibida no console pela seguinte linha de código:
Console.WriteLine();
A função X++ print é usada somente quando você testa. Um programa X++ que usa print quase sempre usa a pause instrução em algum lugar mais tarde no código. Para código X++ de produção, use o método Global::info em vez de print. A strfmt função é frequentemente usada em conjunto com infoo . Não há uma razão para usar pause depois infode .
Faça um som. A função de bipe emite um som que você pode ouvir. Em C#, um som que você pode ouvir é emitido pela seguinte linha de código:
Console.Beep();
Cada uma das declarações produz um tom curto.

Os exemplos de código X++ para loops usam a print função para exibir resultados. Em X++ você pode usar a print instrução pode exibir qualquer tipo de dados primitivo sem ter que chamar funções que o convertem em uma cadeia de caracteres primeiro. Isso é print útil em situações de teste rápido. Geralmente, o método Global::info é usado com mais frequência do que print. O info método só pode exibir cadeias de caracteres. Portanto, a função strfmt é frequentemente usada em conjunto com info. Uma limitação é que você não pode copiar o conteúdo da janela Imprimir para a área de print transferência (como Ctrl+C). Global::info grava na janela Infolog que suporta cópia para a área de transferência.

Exemplo 1: O loop while

A palavra-chave while suporta looping em X++ e C#.

Exemplo de X++ de enquanto

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.
} 
Resultado

A saída na janela de impressão X++ é a seguinte:

1
2
3
4

Exemplo de C# de enquanto

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

A saída do console do programa C# é a seguinte:

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

Exemplo 2: O loop for

A palavra-chave for suporta looping em X++ e C#.

Exemplo de X++ de for

Em X++, a variável de contador não pode ser declarada como parte da instrução 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;
}
Resultado

A saída na janela de impressão X++ é a seguinte:

1
2
3
4

Exemplo de C# de 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();
    }
}
Resultado

A saída do console do programa C# é a seguinte:

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

Comparação X++, C#: Switch

Em X++ e C#, a instrução switch envolve as palavras-chave case, break e default. A tabela a seguir lista as diferenças na instrução switch entre X++ e C#.

Característica X++ C# Comments
break; no final de cada bloco de casos Em X++, quando qualquer bloco de maiúsculas e minúsculas corresponde ao valor da expressão na cláusula switch, todos os outros blocos de maiúsculas e minúsculas e padrão são executados até que uma instrução seja atingida.break; Nenhuma break; instrução é necessária em uma instrução de switch X++, mas break; as instruções são importantes em quase todas as situações práticas. Em C#, uma break; instrução é sempre necessária após as instruções em um bloco de caso ou padrão . Se uma cláusula de caso não tiver instruções entre si e a cláusula de caso seguinte, uma break; declaração não será necessária entre as duas cláusulas de caso . Recomendamos não omitir a break; instrução após qualquer bloqueio de caso, porque isso pode confundir o próximo programador que edita o código.
break;no final do bloco padrão No X++, não há um efeito de adicionar uma break; instrução no final do bloco padrão . Em C#, o compilador requer uma break; instrução no final do bloco padrão . Para obter mais informações, consulte Instruções Switch.
Somente valores constantes em um bloco de maiúsculas e minúsculas No X++, você pode especificar um valor literal ou uma variável em um bloco de maiúsculas e minúsculas. Por exemplo, você pode escrever maiúsculas e minúsculas myInteger:. Em C#, você deve especificar exatamente um valor literal em cada bloco de maiúsculas e minúsculas, e nenhuma variável é permitida. Sem comentários.
Vários valores em um bloco de maiúsculas e minúsculas No X++, você pode especificar vários valores em cada bloco de maiúsculas e minúsculas. Os valores devem ser separados por vírgula. Por exemplo, você pode escrever case 4,5,myInteger:. Em C#, você deve especificar exatamente um valor em cada bloco de maiúsculas e minúsculas . No X++, é melhor escrever vários valores em um bloco de maiúsculas e minúsculas do que omitir a break; instrução no final de um ou mais blocos de maiúsculas e minúsculas.

Exemplos de código para switch

As seções a seguir mostram instruções de switch comparáveis em X++ e C#.

Exemplo de switch X++

O exemplo de opção X++ mostra o seguinte:

  • case iTemp: e case (93-90): para mostrar que as expressões de caso não se limitam a constantes, como em C#.
  • //break; para mostrar que break; as instruções não são necessárias no X++, embora sejam quase sempre desejáveis.
  • case 2, (93-90), 5: para mostrar que várias expressões podem ser listadas em uma cláusula de caso no X++.
static void GXppSwitchJob21(Args _args)  // X++ job in AOT &gt; 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
***

Exemplo de switch C#

O exemplo de opção C# mostra o seguinte:

  • Caso 1: tem um comentário explicando que apenas expressões constantes podem ser dadas em uma cláusula de caso .
  • break; as instruções ocorrem após a última instrução em cada bloco de caso que tem instruções, como é exigido pelo 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
>>
***/

Comparação X++, C#: String Case e Delimitadores

Esta seção compara o tratamento de cadeias de caracteres com caixa mista em X++ e C#. Ele também explica os delimitadores de cadeia de caracteres que estão disponíveis no X++.

Semelhanças

Os seguintes recursos do X++ são os mesmos do C#:

  • A barra invertida (\) é o operador de escape para delimitadores de cadeia de caracteres.
  • O sinal de at (@) anula o efeito de escape da barra invertida quando o sinal de at é escrito imediatamente antes das aspas abertas de uma cadeia de caracteres.
  • O sinal de adição (+) é o operador de concatenação de cadeia de caracteres.

Diferenças

Os recursos do X++ que são diferentes em C# estão listados na tabela a seguir.

Característica X++ C# Comments
== Operador de comparação Insensível: o == operador é insensível a diferenças no invólucro da cadeia de caracteres. Em C#, o == operador é sensível a diferenças na caixa de cadeia de caracteres. No X++, você pode usar a função strCmp para comparações que diferenciam maiúsculas de minúsculas entre cadeias de caracteres.
Delimitadores de cadeia de caracteres No X++, você pode usar as aspas simples (') ou duplas (") como o delimitador de cadeia de caracteres.

Observação: Normalmente, a prática recomendada é usar aspas duplas para cadeias de caracteres que podem ser exibidas para o usuário. No entanto, é conveniente delimitar uma cadeia de caracteres com aspas simples quando uma aspa dupla é um dos caracteres na cadeia de caracteres.

Em C#, você deve usar as aspas duplas como o delimitador de cadeia de caracteres. Isto refere-se ao tipo System.String. Em X++ e C# você tem a opção de incorporar um delimitador em uma cadeia de caracteres literal e escapar dele com .
Em X++ você também tem a alternativa de incorporar aspas simples em uma cadeia de caracteres que é delimitada por aspas duplas (ou o inverso), sem ter que usar o escape.
Delimitadores de caracteres X++ tem um tipo de dados de cadeia de caracteres (str), mas nenhum tipo de caractere. Em C#, você deve usar as aspas simples como o delimitador de caracteres. Isto refere-se ao tipo System.Char. No .NET Framework, um System.String de comprimento um é um tipo de dados diferente de um System.Char caractere.

Exemplo 1: Sensibilidade a maiúsculas e minúsculas do operador ==

Os == operadores e != não diferenciam maiúsculas de minúsculas em X++, mas diferenciam maiúsculas de minúsculas em C#, como ilustrado pelo exemplo a seguir.

X++ C# Comments
"HELLO" == "hello"
True em X++.
"HELLO" == "hello"
Falso em C#.
Comparações de casos diferentes entre X++ e C#.

Exemplo 2: O operador de concatenação + String

Os operadores + e += são usados para concatenar cadeias de caracteres em X++ e C#, como mostram os exemplos na tabela a seguir.

X++ C# Comments
myString1 = "Hello" + " world";
O resultado é a igualdade:
myString1 == "Hello world"
(O mesmo que para X++.) Em X++ e C#, o comportamento do operador + depende do tipo de dados de seus operandos. O operador concatena cadeias de caracteres ou adiciona números.
mystring2 = "Hello";
myString2 += " world";
O resultado é a igualdade: myString2 == "Hello world"
(O mesmo que para X++.) Em X++ e C#, as instruções a seguir são equivalentes:
a = a + b;
a += b;

Exemplo 3: Incorporação e fuga de delimitadores de cadeia de caracteres

As aspas simples ou duplas podem ser usadas para delimitar cadeias de caracteres no X++. O caractere de escape (\) pode ser usado para incorporar delimitadores em uma cadeia de caracteres. Estes são ilustrados no quadro seguinte.

X++ C# Comments
myString1 = "They said \"yes\".";
Resultado:
They said "yes".
(O mesmo que para X++.) O caractere de escape permite incorporar delimitadores de cadeia de caracteres dentro de cadeias de caracteres.
myString2 = 'They said "yes".';
Resultado:
They said "yes".
A sintaxe C# não permite aspas simples para delimitar cadeias de caracteres. Para cadeias de caracteres que podem ser vistas pelo usuário, é considerado uma prática recomendada usar o caractere de escape em vez das aspas simples, como mostrado no exemplo.
myString3 = "They said 'yes'.";
Resultado:
They said 'yes'.
(O mesmo que para X++.) No X++, as aspas simples não são tratadas como delimitadores, a menos que a cadeia de caracteres comece com um delimitador de aspas simples. Em C#, as aspas simples não têm significado especial para cadeias de caracteres e não podem ser usadas para delimitar cadeias de caracteres. Em C#, as aspas simples são o delimitador necessário para literais do tipo System.Char. X++ não tem nenhum tipo de dados de caractere.
str myString4 = 'C';
Aqui, a cotação única é um delimitador de string.
char myChar4 = 'C';
Aqui, as aspas simples são um System.Char delimitador, não um System.String delimitador.
X++ não tem nenhum tipo de dados que corresponde no System.Char .NET Framework. Uma cadeia de caracteres X++ limitada a um comprimento de um ainda é uma cadeia de caracteres, não um tipo de dados de caracteres.

Exemplo 4: Personagem de fuga única

Exemplos que ilustram o caractere de escape único na entrada ou na saída são mostrados na tabela a seguir.

X++ C# Comments
myString1 = "Red\ shoe";
Resultado:
Red shoe
Uma cadeia de caracteres literal em C# não pode conter a sequência de dois caracteres de fuga seguida por um espaço, como "\ ". Ocorre um erro de compilador. Quando o compilador X++ encontra a sequência de dois caracteres de "\ ", ele descarta o único caractere de escape.
myString2 = "Red\\ shoe";
Resultado:
Red\ shoe
(O mesmo que para X++.) Em um par de caracteres de fuga, o primeiro nega o significado especial do segundo.

Comparação: Sintaxe da matriz

Há semelhanças e diferenças nos recursos e sintaxe para matrizes em X++ versus C#.

Semelhanças

No geral, há muita semelhança na sintaxe e no tratamento de matrizes em X++ e C#. No entanto, existem muitas diferenças.

Diferenças

A tabela a seguir lista áreas na sintaxe [] para matrizes que são diferentes para X++ e C#.

Categoria X++ C# Comments
Declaração Uma matriz é declarada com colchetes anexados ao nome da variável. Uma matriz é declarada com colchetes anexados ao tipo de dados. int myInts[]; // X++

Observação: Uma matriz X++ não pode ser um parâmetro em um método.

int[] myInts; // C#

Declaração A sintaxe da matriz suporta apenas tipos de dados primitivos, como int e str. A sintaxe não suporta classes ou tabelas. A sintaxe da matriz suporta tipos de dados primitivos e classes. Em X++ você pode usar a Array matriz para uma matriz de objetos.
Declaração X++ é limitado a matrizes de dimensão única (myStrings[8]). O C# adiciona suporte para matrizes multidimensionais (myStrings[8,3]) e para matrizes irregulares (myStrings[8][3]). No X++ você não pode ter uma matriz de matrizes. No entanto, há sintaxe avançada para limitar a quantidade de memória ativa que uma matriz grande pode consumir, que se parece com a sintaxe multidimensional em C#: int intArray[1024,16];. Para obter mais informações, consulte Otimizações de desempenho de práticas recomendadas: trocando matrizes para disco.
Declaração Em X++, uma matriz é uma construção especial, mas não é um objeto. Em C#, todas as matrizes são objetos, independentemente das variações de sintaxe. X++ tem uma classe Array, mas seu mecanismo subjacente difere de matrizes criadas usando a sintaxe []. Em C#, todas as matrizes usam o mesmo mecanismo subjacente, independentemente de [] sintaxe da System.Array classe ser usada em seu código.
Length Em X++, o comprimento de uma matriz de tamanho estático é determinado na sintaxe da declaração. Em C#, o tamanho de uma matriz é determinado quando o objeto de matriz é construído. Quando você usa a sintaxe de declaração [] no X++, não é necessária mais preparação antes de atribuir valores à matriz.
Em C#, você deve declarar e, em seguida, construir a matriz antes de atribuir a ela.
Length Uma matriz X++ pode ter um comprimento dinâmico que pode ser aumentado mesmo após o início da população. Isso se aplica somente quando a matriz é declarada sem um número dentro do []. O desempenho pode ser reduzido se o comprimento da matriz dinâmica for aumentado muitas vezes. Em C#, o comprimento de uma matriz não pode ser alterado depois que o comprimento é definido. No fragmento seguinte do código X++, apenas a myInts matriz é dinâmica e pode aumentar de tamanho.
int myInts[];
int myBools[5];
myInts[2] = 12;
myInts[3] = 13;
myBools[6] = 26; //Error
Length Você pode obter o comprimento de algumas matrizes usando a dimOf função. Matrizes C# são objetos que têm uma Length propriedade. Sem comentários.
Indexação A indexação de matrizes é baseada em 1. A indexação de matrizes é baseada em 0. mtIntArray[0] causaria um erro no X++.
Constante Em X++, um valor constante é melhor alcançado usando a diretiva #define precompiler. Em C# você pode decorar sua declaração variável com a palavra-chave const, para obter um valor constante. X++ não tem palavra-chave const . C# não pode atribuir valores a variáveis que são criadas por seu #define diretiva pré-compilador.

Exemplos de X++ e C#

Os exemplos de código a seguir mostram como matrizes de tipos de dados primitivos são tratadas. O primeiro exemplo está em X++ e o segundo exemplo está em C#. Ambas as amostras alcançam os mesmos resultados.

Exemplo de 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]));
    }
}
Resultado

A saída para o Infolog é a seguinte:

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

Exemplo de 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
Resultado

A saída do programa C# para o console de linha de comando é a seguinte:

-------- 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]

Recursos X++ adicionais semelhantes a arrays

O contêiner é um tipo de dados especial que está disponível no X++. Pode ser considerado semelhante a uma matriz, ou semelhante a uma List coleção.

Comparação: Coleções

Em um aplicativo de finanças e operações, você pode usar a classe de coleção X++ List . O .NET Framework que é usado em C# tem uma classe semelhante chamada System.Collections.Generic.List.

Comparando o uso das classes de lista

A tabela a seguir compara métodos na classe X++ List com os métodos do System.Collections.Generic.List .NET Framework e C#.

Característica X++ C# Comments
Declaração de recolha List myList; List<string> myList; A declaração X++ não inclui o tipo de elementos a serem armazenados.
Declaração do iterador ListIterator iter
ListEnumerator enumer;
IEnumerator<string> iter; Em X++ o ListIterator objeto tem métodos que podem insert e delete itens do List. O X++ ListEnumerator não pode modificar o conteúdo do List. No X++, o ListEnumerator objeto é sempre criado na mesma camada que o List. Isto nem sempre é verdade para ListIterator.
Obtendo um iterador new ListIterator (myList)
myList.getEnumerator()
myList.GetEnumerator() Em X++ e C#, o objeto List tem um método getter para um enumerador associado.
Construtor new List(Types::String) new List<string>() Informações sobre o tipo de objetos a serem armazenados dentro das List classes são dadas ao construtor em X++ e C#.
Atualização de dados Enumerador – o enumerador torna-se inválido se algum item no List for adicionado ou removido.
Iterador – o iterador tem métodos que inserem e excluem itens do List. O iterador permanece válido.
Enumerador – o enumerador torna-se inválido se algum item no List for adicionado ou removido. Os enumeradores tornam-se inválidos depois que os itens são adicionados ou excluídos do List, em X++ e C#.
Atualização de dados Em X++ a List classe tem métodos para adicionar itens no início ou no final da lista. Em C#, a List classe tem métodos para adicionar membros em qualquer posição na lista. Ele também tem métodos para remover itens de qualquer posição. No X++, os itens podem ser removidos do List somente por um iterador.

Exemplo 1: Declaração de uma lista

Os exemplos de código a seguir estão em X++ e C# que declaram List coleções.

// X++
List listStrings ,list2 ,listMerged;
ListIterator literator;
// C#
using System;
using System.Collections.Generic;
List<string> listStrings ,list2 ,listMerged; IEnumerator<string> literator;

Exemplo 2: Construção de uma lista

Em ambos os idiomas, o tipo de itens que a coleção armazena deve ser especificado no momento da construção. Para tipos de classe, X++ não pode obter mais específico do que se o tipo é uma classe (Types::Class). Os exemplos de código a seguir estão em X++ e C#.

// X++
listStrings = new List( Types::String );
// C#
listStrings = new List<string>;

Exemplo 3: Adicionar itens a uma lista

Em X++ e C#, a coleção fornece um método para anexar um item ao final da coleção e para inserir um item no início. Em C#, a coleção fornece um método para inserir em qualquer ponto da coleção com base em um valor de índice. No X++, um iterador de coleção pode inserir um item em sua posição atual. Os exemplos de código a seguir estão em 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");

Exemplo 4: Iterar através de uma lista

Tanto o X++ quanto o C# têm classes de iterador que você pode usar para percorrer os itens em uma coleção, conforme mostrado nos exemplos a seguir.

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

Exemplo 4b: foreach em C#

Em C#, a palavra-chave foreach é frequentemente usada para simplificar a tarefa de iterar através de uma lista. O exemplo de código a seguir se comporta da mesma forma que o exemplo C# anterior.

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

Exemplo 5: Excluir o segundo item

Os exemplos de código a seguir excluem o segundo item da coleção. No X++, isso requer um iterador. Em C#, a própria coleção fornece o método para remover um item.

// X++
literator.begin(); 
literator.next(); 
literator.delete();
// C#
listStrings.RemoveAt(1);

Exemplo 6: Combinar duas coleções

Os exemplos de código a seguir combinam o conteúdo de duas coleções em uma.

// X++
listStrings = List::merge(listStrings ,listStr3);
// Or use the .appendList method:
listStrings.appendList (listStr3);
// C#
listStrings.InsertRange(listStrings.Count ,listStr3);

Comparação: Coleções de chaves com valores

Em um aplicativo de finanças e operações, você pode usar a Map classe collection. A Map coleção contém pares de valores, o valor da chave mais um valor de dados. Isso é semelhante à classe .NET Framework chamada System.Collections.Generic.Dictionary.

Semelhanças

A lista a seguir descreve semelhanças entre X++ e C# em relação às suas coleções que armazenam pares chave-valor:

  • Ambos evitam chaves duplicadas.
  • Ambos usam um enumerador (ou iterador) para percorrer os itens.
  • Ambos os objetos de coleção chave-valor são construídos com designações dos tipos que são armazenados como chave e valor.
  • Ambos podem armazenar objetos de classe e não estão limitados a armazenar primitivos como int.

Diferenças

A tabela a seguir descreve as diferenças entre X++ e C# em relação às suas classes de coleções que armazenam pares chave-valor:

Característica X++ C# Comments
Chaves duplicadas Em X++, a Map classe impede chaves duplicadas tratando implicitamente sua chamada para seu insert método como uma operação para atualizar apenas o valor associado à chave. Em C#, a Dictionary classe lança uma exceção quando você tenta adicionar uma chave duplicada. Chaves duplicadas são evitadas em ambos os idiomas, embora por técnicas diferentes.
Excluir itens Em X++, o delete método em um objeto iterador é usado para remover um par chave-valor indesejado de um Maparquivo . Em C# a Dictionary classe tem um remove método. Em ambos os idiomas, um enumerador se torna inválido se a contagem de itens de coleção for modificada durante a vida do enumerador.

Exemplo 1: Declaração de uma coleção Key-Value

Em ambos os idiomas, o tipo de itens que a coleção de chave-valor armazena deve ser especificado. Em X++ o tipo é especificado no momento da construção. Em C#, o tipo é especificado no momento da declaração e no momento da construção. Os exemplos de código a seguir estão em 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;

Exemplo 2: Construção da coleção

Em ambos os idiomas, o tipo de itens que a coleção chave-valor armazena especificado durante a construção. Para tipos de classe, X++ não pode obter mais específico do que se o tipo é uma classe (Types::Class). Os exemplos de código a seguir estão em X++ e C#.

// X++
mapKeyValue = new Map(Types::Integer, Types::String);
// C#
dictKeyValue = new Dictionary<int,string>();

Exemplo 3: Adicionar um item à coleção

Quase não há diferença em como um item é adicionado a uma coleção de chave-valor em X++ e C#, conforme mostrado nos exemplos de código a seguir.

// X++
mapKeyValue.insert(xx ,int2str(xx) + “_Value”);
// C#
dictKeyValue.Add(xx ,xx.ToString() + “_Value”);

Exemplo 4: Iterar através de uma coleção Key-Value

Os enumeradores são usados para percorrer as coleções de chave-valor em X++ e C#, conforme mostrado nos exemplos de código a seguir.

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

Exemplo 5: Atualizar o valor associado a uma chave

A sintaxe é muito diferente entre os dois idiomas para uma atualização do valor associado a uma determinada chave. Os exemplos de código ollowing são para a chave 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.”;

Exemplo 6: Excluir um item

A sintaxe é muito diferente entre os dois idiomas para excluir um par chave-valor de uma coleção, enquanto itera pelos membros da coleção. Exemplos de código para a chave 102 são mostrados abaixo.

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

Comparação: Exceções

Existem algumas semelhanças, mas muitas diferenças quando comparamos o comportamento relacionado a exceções entre X++ e C#. As palavras-chave try, catch e throw se comportam da mesma forma em X++ e C#. Mas os tipos de exceções lançadas e apanhadas são diferentes para as duas línguas.

Semelhanças

As semelhanças entre X++ e C# em relação aos seus recursos de exceção incluem os seguintes exemplos:

  • Ambas as línguas têm a mesma palavra-chave try .
  • Ambos têm a mesma palavra-chave catch .
  • Ambos habilitam uma instrução catch que não especifica nenhuma exceção específica. Essa declaração de captura captura todas as exceções que a atingem.
  • Ambos têm a mesma palavra-chave.

Diferenças

As diferenças relacionadas a exceções entre X++ e C# são descritas na tabela a seguir.

Característica X++ C# Comments
retentar Salta para a primeira instrução no bloco try associado. Para obter mais informações, consulte Tratamento de exceções com palavras-chave try and catch. A funcionalidade da palavra-chave retry pode ser imitada no código C#, mas não há uma palavra-chave correspondente. Apenas X++ tem uma palavra-chave retry . C# não tem contrapartida. Para obter mais informações, consulte X++, C# Comparison: Automated Retry After an Exception.
finalmente A finally palavra-chave é suportada para seguir as try palavras-chave e catch . A palavra-chave finally marca um bloco de código que segue os blocos try and catch . A última será executada independentemente de qualquer exceção ser lançada ou capturada. A semântica é idêntica à semântica em C#.
Exceções específicas No X++, uma exceção é um elemento do Exception enum, como Error, Deadlock ou CodeAccessSecurity. Nenhuma exceção pode conter outra. Em C#, uma exceção é uma instância da System.Exception classe base ou qualquer classe que herda dela. Uma exceção pode estar contida na InnerException propriedade da exceção lançada. No X++, cada exceção lançada é um valor do enum Exception. Para obter mais informações, consulte Enumeração de exceções.
Mensagem de exceção No X++, a mensagem criada quando uma exceção é gerada está disponível somente no Infolog e a mensagem não está diretamente vinculada à exceção. Em C#, a mensagem é o MessageSystem.Exception membro do objeto. Em X++, o método Global::error é o mecanismo que exibe mensagens de exceção no Infolog. Para obter mais informações, consulte Tratamento de exceções com palavras-chave try and catch.
Condições de exceção No X++, um erro ocorre quando você chama um método de instância em uma variável de objeto que ainda não teve nada atribuído a ele. No entanto, nenhuma exceção é levantada junto com esse erro. Portanto, nenhum catch bloco pode obter controle, mesmo se a variável não atribuída for usada indevidamente em um try bloco. No exemplo de código a seguir, o erro causado pelo código box4.toString(); não faz com que o controle seja transferido para qualquer catch bloco: DialogBox box4;try { box4.toString(); info("toString did not error, but expected an error."); } catch (Exception::Error) // Nenhum valor de exceção captura isso. info("Invalid use of box4 gave control to catch, unexpected."); { } Em C#, a System.NullReferenceException é gerado quando uma variável não inicializada é tratada como uma referência de objeto. Pode haver várias outras diferenças nas condições que suscitam exceções.
Transações SQL Em X++, quando ocorre uma exceção SQL em uma transação ttsBegin - ttsCommit , nenhuma instrução catch dentro do bloco de transação pode processar a exceção. Em C#, um bloco catch dentro de uma transação SQL pode capturar a exceção.

Examples

Os seguintes recursos X++ são demonstrados:

  • tente a palavra-chave.
  • palavra-chave catch .
  • O comportamento após uma exceção Exception::Error ocorre.

Exemplo de 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.");
}
Resultado

Aqui está a saída da janela 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.

Exemplo de C#

O seguinte programa C# é uma reescrita do programa X++ anterior.

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

Aqui está a saída para o console C#:

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

Comparação: Repetição automatizada após uma exceção

Às vezes, você pode escrever código em um bloco catch que corrige a causa de uma exceção que ocorre durante o tempo de execução. X++ fornece uma palavra-chave retry que pode ser usada apenas dentro de um bloco catch . A palavra-chave retry permite que um programa volte para o início do bloco try depois que o problema foi corrigido pelo código no bloco catch . C# não tem uma palavra-chave de nova tentativa . No entanto, o código C# pode ser escrito para fornecer um comportamento equivalente.

Exemplos de código para repetição

O seguinte programa de exemplo X++ faz com que um Exception::Error seja gerado. Isso ocorre quando ele tenta ler pela primeira vez um elemento da sStrings matriz usando um valor de índice inválido. Quando a exceção é capturada, uma ação corretiva é tomada durante o tempo de execução dentro do bloco de captura . Em seguida, a instrução retry volta para a primeira instrução no bloco try . Esta segunda iteração funciona sem encontrar qualquer exceção.

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

Resultado

Aqui está a saída para a janela Imprimir:

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.

Exemplo de C#

O exemplo de C# a seguir não é uma tradução linha por linha do exemplo X++ anterior. Em vez disso, o programa C# tem uma estrutura diferente para que ele imita o comportamento da palavra-chave retry na qual o programa X++ depende. Os blocos try e catch estão em um método chamado. As variáveis usadas no bloco try são armazenadas no método do chamador. O método chamador passa as variáveis como parâmetros que são decorados com a palavra-chave ref , para que seus valores possam ser corrigidos dentro do bloco catch do método chamado. O método chamado captura todas as exceções e retorna um booleano para comunicar de volta ao chamador se uma segunda chamada é necessária.

// 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;
    }
}

Resultado

Aqui está a saída para o 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.

Comparação: Operadores

Esta seção compara os operadores entre X++ e C#.

Operadores de Atribuição

A tabela a seguir exibe as diferenças entre os operadores de atribuição em X++ e C#.

X++ e C# Diferenças
= Em X++, esse operador causa uma conversão implícita sempre que uma perda de precisão pode ocorrer, como para uma atribuição de um int64 para um int. Mas em C# a atribuição causa um erro de compilação.
+= e -= A única diferença é que em C# esses operadores também são usados na manipulação de delegados.
++ e -- Estes são os operadores de incremento e decréscimo em ambas as línguas. A seguinte linha é idêntica em ambas as línguas:
++myInteger;
Mas em X++ esses dois operadores são para instruções, não para expressões. Portanto, as seguintes linhas geram erros de compilação no X++:
myStr = int2str(++myInteger);
myIntA = myIntBB++;

Operadores Aritméticos

A tabela a seguir lista os operadores aritméticos.

X++ e C# Diferenças
* Como operador de multiplicação, não há diferenças.

Observação: O asterisco também é usado nas instruções SQL que fazem parte da linguagem X++. Nessas instruções SQL, o asterisco também pode ser um dos seguintes:

  • Um curinga indicando que todas as colunas devem ser retornadas.
  • Um curinga para caracteres em uma cadeia de caracteres que é usada em uma cláusula semelhante .
/ O operador de divisão é o mesmo em X++ e C#.
MOD Para operações de módulo, a única diferença é que o símbolo % é usado em C#.
+ O operador de adição é o mesmo em X++ e C#. O sinal de adição também é usado para concatenação de cordas. Este operador adiciona números e concatena cadeias de caracteres em ambos os idiomas.
- O operador de subtração é o mesmo em X++ e C#.

Operadores Bitwise

A tabela a seguir compara os operadores bitwise entre X++ e C#.

X++ e C# Diferenças
<< O operador de turno à esquerda é o mesmo em X++ e C#.
>> O operador de deslocamento à direita é o mesmo em X++ e C#.
~ O operador bit a bit NOT é o mesmo em X++ e C#.
& O operador binário AND é o mesmo em X++ e C#.
^ O operador XOR binário é o mesmo em X++ e C#.

Operadores Relacionais

Os seguintes operadores relacionais são os mesmos em X++ e C#:

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

Comparação: Eventos

Há algumas diferenças em como X++ e C# implementam o padrão de design de evento. Para obter mais informações, consulte Terminologia de eventos e palavras-chave.

Comparação de eventos entre X++ e C#

Há diferenças na maneira como os delegados são usados para eventos em X++ versus C#.

Concept X++ C# Comments
delegate No X++, um delegado pode ser declarado apenas como membro de uma classe. Um delegado não pode ser membro de uma mesa. Todos os delegados são membros de instância de sua classe, não membros estáticos . Nenhum modificador de acesso pode ser usado em uma declaração de delegado, porque todos os delegados são membros protegidos . Portanto, o evento só pode ser gerado por código dentro da mesma classe em que o delegado é membro. No entanto, a única exceção à natureza privada de um delegado é que o código fora de sua classe pode operar nos delegados usando os operadores += e -=. Em C#, cada delegado é um tipo, assim como cada classe é um tipo. Um delegado é declarado independentemente de qualquer classe. Sem a palavra-chave de evento , você pode ter um delegado como um tipo de parâmetro em um método, assim como você pode ter uma classe como um tipo de parâmetro. Você pode construir uma instância de um delegado para transmitir o valor do parâmetro. No X++, cada classe é um tipo, mas nenhum delegado é um tipo. Não é possível construir uma instância de um delegado. Nenhum delegado pode ser um parâmetro para um método. Mas você pode criar uma classe que tenha um membro delegado e pode passar instâncias da classe como valores de parâmetro. Para obter mais informações, consulte Palavras-chave X++.
evento No código X++, um evento é um dos seguintes:
  • Uma chamada explícita para um delegado.
  • O início ou fim de um método.
Não há uma palavra-chave de evento no X++.
Em C#, a palavra-chave de evento é usada para declarar um tipo de delegado como membro de uma classe. O efeito da palavra-chave de evento é tornar o delegado protegido, mas ainda acessível para os operadores += e -=. Você pode inscrever métodos de manipulador de eventos em um evento usando o operador +=. Um delegado pode ser útil sem a palavra-chave do evento , como uma técnica para passar um ponteiro de função como um parâmetro para um método. Os eventos automáticos que ocorrem antes do início de um método, e após o final de um método, podem ser inscritos somente usando a AOT.
+= e -= operadores Em X++, você usa o operador += para assinar métodos para um delegado. O operador -= cancela a assinatura de um método de um delegado. Em C#, você usa o operador += para inscrever métodos em um evento ou em um delegado que não é usado com a palavra-chave do evento . O delegado contém uma referência a todos os objetos que têm métodos inscritos para o delegado. Esses objetos não são elegíveis para coleta de lixo enquanto o delegado mantém essas referências.
eventHandler Em X++, a palavra-chave eventHandler é necessária quando você usa o operador += ou -= para assinar ou cancelar a assinatura de um método de um delegado. System.EventHandler é um tipo de delegado no .NET Framework. Esse termo é usado de forma diferente no X++ do que no C# ou no .NET Framework. Para obter mais informações, consulte Palavras-chave X++.

Exemplo de X++

As coisas importantes a observar são as seguintes no exemplo X++:

  • O XppClass tem um membro delegado que é chamado myDelegate.

    Observação

    O AOT contém um nó para o delegado. O nó está localizado em AOT > Classes > XppClass > myDelegate. Vários nós do manipulador de eventos podem ser localizados sob o nó myDelegate. Os manipuladores de eventos representados por nós na AOT não podem ser removidos pelo operador -= durante o tempo de execução.

  • As {} chaves no final da declaração de delegado são obrigatórias, mas não podem ter nenhum código nelas.

  • O XppClass tem dois métodos cujas assinaturas de parâmetros são compatíveis com o delegado. Um método é estático.

  • Os dois métodos compatíveis são adicionados ao delegado com o operador += e a palavra-chave eventHandler . Essas instruções não chamam os métodos do manipulador de eventos, as instruções apenas adicionam os métodos ao delegado.

  • O evento é gerado por uma chamada para o delegado.

  • O valor do parâmetro que passou para o delegado é recebido por cada método manipulador de eventos.

  • O trabalho X++ curto na parte superior do exemplo inicia o teste.

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

A saída do trabalho X++ anterior é a seguinte:

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.

Exemplo de C#

Esta seção contém um exemplo de código C# para o padrão de design de evento do exemplo X++ anterior.

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

A saída do exemplo C# anterior é a seguinte:

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.

Eventos e o AOT

Existem outros sistemas de eventos que se aplicam apenas a itens na AOT. Para obter mais informações, consulte Nós do manipulador de eventos na AOT.

Comparação: Diretivas pré-compiladoras

X++ e C# compartilham algumas palavras-chave para sua sintaxe de diretiva pré-compiladora, mas os significados nem sempre são os mesmos.

Semelhanças

Os compiladores X++ e C# reconhecem muitas das mesmas palavras-chave. Na maioria dos casos, as palavras-chave significam o mesmo para ambos os compiladores de linguagem.

Diferenças

Uma diferença fundamental entre as diretivas de pré-compilador em X++ versus C# é a palavra-chave #define que ambos os pré-compiladores de linguagem reconhecem. Ao contrário do C#, em X++ a diretiva #define requer um ponto em sua sintaxe. Em X++, parênteses podem ser usados para dar um valor ao símbolo definido. Essas diferenças são mostradas nos seguintes exemplos:

  • Em X++: #define. Ano Inicial(2003)
  • Em C#: #define InitialYear

Uma pequena diferença é que em C# pode haver espaços e caracteres de tabulação entre o caractere # e a palavra-chave diretiva, como # define Testing.

Palavras-chave idênticas

A tabela a seguir lista diretivas de pré-compilador que são semelhantes em X++ e C#.

Keyword X++ C# Comments
#define Em X++, um nome de variável pré-compilador pode ser definido e um valor pode ser dado a essa variável. Em C#, um nome de variável pré-compilador pode ser definido, mas nenhum valor pode ser dado a essa variável. Além disso, qualquer #define em C# deve ocorrer na parte superior do arquivo e não pode ocorrer após qualquer código, como uma instrução using ou uma declaração de classe. O compilador C# pode inserir um parâmetro de linha de comando para definir um nome de variável pré-compilador sem definir a variável em qualquer arquivo de /define código C#. O compilador X++ não tem contrapartida para /define.
#if Em X++, #if pode determinar se uma variável pré-compiladora existe e se a variável tem um determinado valor. Em C#, #if só pode determinar se existe uma variável pré-compiladora. Ele não pode testar qualquer valor porque nenhum valor pode ser atribuído.
#endif No X++, #endif marca o fim de um bloco #if. Também encerra um #ifnot bloco. Em C#, #endif marca o fim de um bloco #if, independentemente de o bloco incluir um #else.

Palavras-chave diferentes com o mesmo resultado de processamento

A tabela a seguir lista diretivas de pré-compilador que são nomeadas de forma diferente em X++ e C#, mas que fornecem os mesmos resultados quando processadas.

X++ C# Comments
#ifnot #if #else Não há uma diretiva #else no X++, mas o #ifnot fornece funcionalidade semelhante. No X++, #ifnot pode determinar se existe uma variável pré-compiladora e se a variável não tem um determinado valor específico. Em C#, #if pode determinar se uma variável pré-compiladora existe quando o '!' é prefixado ao nome da variável.
//BP Deviation documented #pragma advertência Essas entradas X++ e C# não são equivalentes, mas há uma semelhança parcial. Ambos suprimem mensagens de aviso do compilador.
#macrolib . Arquivo HPP em C++ Há uma semelhança parcial entre a diretiva X++ #macrolib versus um . Arquivo HPP em C++. Ambos podem conter várias declarações #define.

Diretivas de pré-compilador exclusivas para X++

A tabela a seguir lista as diretivas de pré-compilador X++ que não têm contrapartida direta em C#.

X++ Comments
#linenumber A diretiva #linenumber é para obter o número da linha, para que ele possa ser enviado para o Infolog.
A diretiva C# #line é diferente porque sua finalidade é definir o número da linha.
#defdec #definc
#globaldefine No X++, há uma pequena diferença entre #globaldefine e #define. A diferença é que #globaldefine nunca substitui um valor não nulo atual que foi atribuído a uma variável de pré-compilador por #define.
C# não tem nada semelhante a essa diferença, porque em C#, um nome de variável pré-compilador não pode receber um valor.
#localmacro #macro No X++, #localmacro permite atribuir um valor de várias linhas a uma variável pré-compiladora. #macro é sinónimo, mas #localmacro é recomendado.
Em C#, a diretiva #define tem parte dessa funcionalidade, mas não pode atribuir um valor a uma variável pré-compiladora.
#globalmacro No X++, #globalmacro é quase o mesmo que o #localmacro preferido.

Comparação: Programação Orientada a Objetos

Os princípios de programação orientada a objetos (OOP) do X++ diferem do C#.

Comparações conceptuais

A tabela a seguir compara a implementação de princípios OOP entre X++ e C#.

Característica X++ C# Comments
Fundição A linguagem X++ tem as palavras-chave is e as, que são usadas para tornar os downcasts seguros e explícitos. Dica: X++ não requer o uso da palavra-chave as quando você faz downcast de uma variável de classe base para uma variável de classe derivada. No entanto, recomendamos que todas as declarações downcast usem a palavra-chave as . Um objeto pode ser lançado para cima ou para baixo no caminho de herança. Os abatidos, exigem a palavra-chave como . Para obter mais informações sobre as palavras-chave X++ is e as, consulte Operadores de expressão: é e como para herança.
Funções locais Um método pode conter uma declaração e um corpo de código para zero ou mais funções locais. Somente esse método pode ter chamadas para a função local. O C# 3.0 suporta expressões lambda, que têm alguma semelhança com funções anônimas e funções locais. As expressões lambda são frequentemente usadas com delegados.
Sobrecarga do método Não há suporte para sobrecarga de método. Um nome de método pode ocorrer apenas uma vez por classe. A sobrecarga de método é suportada. Um nome de método pode ocorrer várias vezes em uma classe, com assinaturas de parâmetros diferentes em cada caso. X++ suporta parâmetros opcionais em métodos. Os parâmetros opcionais podem imitar parcialmente a sobrecarga do método. Para obter mais informações, consulte a linha para parâmetros opcionais nesta tabela.
Substituição do método A substituição de método é suportada. Uma classe derivada pode ter um método com o mesmo nome da classe base, desde que a assinatura do parâmetro seja a mesma em ambos os casos. A única exceção é que o método de substituição pode adicionar um valor padrão a um parâmetro. A substituição de método é suportada. A palavra-chave virtual deve ser aplicada a um método antes que o método possa ser substituído em uma classe derivada. O conceito de substituir um método inclui o nome do método, sua assinatura de parâmetro e seu tipo de retorno. O conceito de substituição de método não se aplica se o método de base e o método de substituição diferirem em qualquer um desses aspetos.
Parâmetros opcionais Uma declaração de parâmetro pode ser seguida por uma atribuição de valor padrão. O chamador do método tem a opção de passar um valor para esse parâmetro ou ignorar o parâmetro para aceitar o valor padrão. Esse recurso imita a sobrecarga do método porque duas chamadas para o mesmo nome de método podem passar números diferentes de parâmetros. Cada parâmetro que tem um valor padrão deve seguir o último parâmetro que não tem um valor padrão. Os parâmetros opcionais são suportados pela palavra-chave params . Mesmo sem a palavra-chave params , do ponto de vista do chamador, a sobrecarga do método pode fornecer funcionalidade parcialmente semelhante. Para obter mais informações, consulte Parâmetros e escopo e Usando parâmetros opcionais.
Herança única Você pode derivar sua classe X++ de outra classe X++ usando a palavra-chave extends no nó classDeclaration de sua classe, no AOT. Nenhuma classe deriva implicitamente diretamente de outra classe. Se você quiser que sua classe derive diretamente da Object classe, você deve usar a palavra-chave extend . Você pode especificar apenas uma classe na palavra-chave extend .

Cuidado: Quando você modifica uma classe base X++ da qual outras classes derivam, você deve recompilar essa classe base usando o Compile forward. Essa opção garante que as classes derivadas também sejam recompiladas. Para garantir que as classes derivadas também sejam recompiladas, clique com o botão direito do mouse no nó da classe base e clique em Add-Ins > Compilar para frente. A alternativa de clicar em Build > Compile (ou pressionar a tecla F7) às vezes é insuficiente para uma alteração de classe base.

Uma classe pode implementar zero a muitas interfaces.

Uma tabela X++ herda implicitamente da Common tabela e da xRecord classe.
C# usa a palavra-chave extends para derivar de outra classe. Todas as classes do .NET Framework derivam implicitamente da classe, a menos que derivem explicitamente de System.Object outra classe.

Comparações de palavras-chave

A tabela a seguir lista as palavras-chave relacionadas ao OOP em X++ e C#.

Keyword X++ C# Comments
RESUMO Não há diferença.
classe Os modificadores público e privado são ignorados nas declarações de classe. Não há um conceito de um agrupamento de classes de namespace. Não há pontos (.) em nenhum nome de classe. Os modificadores público e privado podem ser usados para modificar declarações de classe. C# também tem a palavra-chave internal, que se relaciona a como as classes são agrupadas em arquivos de assembly. Não existe o conceito de uma classe protegida , apenas membros protegidos de uma classe.
estende-se Uma declaração de classe pode herdar de outra classe usando a palavra-chave extend . Os dois pontos (:) são usados onde as palavras-chave se estendem e os implementos são usados no X++.
Finais Um método final não pode ser substituído em uma classe derivada. Uma aula final não pode ser estendida. A palavra-chave selada em uma classe significa a mesma coisa que final significa em uma classe X++.
implementa Uma declaração de classe pode implementar uma interface usando a palavra-chave implements .
interface Uma interface pode especificar métodos que a classe deve implementar. Uma interface pode especificar métodos que a classe deve implementar.
Novo A nova palavra-chave é usada para alocar uma nova instância de uma classe. Em seguida, o construtor é chamado automaticamente. Cada classe tem exatamente um construtor, e o construtor é chamado new. Você pode decidir quais parâmetros o construtor deve inserir. A nova palavra-chave é usada para criar uma nova instância de uma classe. Em seguida, o construtor é chamado automaticamente. Os métodos do construtor em si não são nomeados new, eles têm o mesmo nome que a classe.

Observação: A nova palavra-chave também pode ser usada em um método, para modificar a maneira como o método substitui o mesmo método na classe base.

X++ e C# assumem um construtor padrão para classes que não têm nenhum construtor explicitamente escrito em seu código.
null Não há diferença.
privado e protegido As palavras-chave privadas e protegidas podem ser usadas para modificar a declaração de um membro da classe. As palavras-chave privadas e protegidas podem ser usadas para modificar a declaração de um membro da classe.
public Um método que não é modificado com público, protegido ou privado tem o nível de acesso padrão de público. Um método que não é modificado com público, protegido ou privado tem o nível de acesso padrão de privado.
estática Um método pode ser estático, mas um campo não. Ambos os métodos e campos podem ser estáticos.
super A superpalavra-chave é usada em uma classe derivada para acessar o mesmo método em sua classe base. void method2()
{
// Call method2 method
// on the base class.
super();
}
A palavra-chave base é usada em uma classe derivada para acessar vários métodos em sua classe base.
void method2()
{
// Call methods on
// the base class.
base.method2();
base.method3();
}
Em C#, há sintaxe especial para usar base para chamar o construtor base.
isto Para uma chamada de um método de instância para outro no mesmo objeto, um qualificador para o método chamado é necessário. A palavra-chave this está disponível como um qualificador para o objeto atual. Para uma chamada de um método de instância para outro no mesmo objeto, um qualificador para o método chamado não é necessário. No entanto, a palavra-chave this está disponível como um qualificador para o objeto atual. Na prática, a palavra-chave isso pode ser útil exibindo informações do IntelliSense.
finalize A Object classe contém o finalize método. O finalize método não é definitivo e pode ser anulado. O finalize método parece se System.Object.Finalize assemelhar ao método em C#, mas em X++ o finalize método não tem nenhum significado especial de qualquer tipo. Um objeto é removido automaticamente da memória quando a última referência ao objeto para de fazer referência ao objeto. Por exemplo, isso pode acontecer quando a última referência sai do escopo ou é atribuído outro objeto à referência. Os métodos Finalize e Dispose são comuns em alguns tipos de classes. O coletor de lixo chama os Finalize métodos e Dispose quando destrói e objeta. Em C#, o System.GC.Collect método no .NET Framework pode ser chamado para iniciar o coletor de lixo. Não há uma função semelhante no X++ porque o X++ usa um coletor de lixo determinístico.
main As classes que são invocadas a partir de um menu têm seu main método chamado pelo sistema. As classes que são invocadas a partir de um console de linha de comando têm seu Main método chamado pelo sistema.

Comparação: Classes

Quando você usa C# no .NET Framework, as classes são agrupadas em namespaces. Cada namespace se concentra em uma área funcional, como operações de arquivo ou reflexão. No entanto, quando você usa as classes no X++, não há agrupamentos visíveis como um namespace.

Comparação: Aulas sobre Reflexão

No X++, a TreeNode classe fornece acesso à árvore de objetos do aplicativo (AOT). A TreeNode classe é o centro da funcionalidade de reflexão no X++. A TreeNode classe e seus métodos podem ser comparados ao System.Reflection namespace no .NET Framework que o C# usa.

A tabela a seguir lista várias classes que estão disponíveis para você quando você escreve código C#. Estas são classes do .NET Framework. Para esta tabela, todas as classes C# estão no namespace, a System.Reflection menos que especificado de outra forma. Cada linha mostra a classe correspondente, ou membro da classe, que está disponível para você quando você escreve código X++.

X++ C# Comments
TreeNode System .Assembly Assembly é a primeira classe a ser usada quando um programa em C# deve reunir informações de reflexão. Os métodos estáticos na classe TreeNode X++ são o ponto de partida para reflexão no X++.
TreeNode System .Type Os métodos de instância em correspondem TreeNode aos métodos de instância em System.Type.
TreeNode .AOTgetSource MethodInfo O AOTgetSource método retorna várias informações juntas em uma cadeia de caracteres. Isso inclui o código-fonte X++ no método. Em contrapartida, MethodInfo tem um membro separado para cada informação.
TreeNode .AOTfirstChild TreeNode .AOTnextSibling TreeNode .AOTiterator AOTiterator MethodInfo[] (uma matriz) Em C#, o GetMethods método on System.Type retorna uma matriz de objetos MethodInfo. Você pode percorrer a matriz pela técnica comum de incrementar um indexador. Em contraste, o modelo X++ é navegar no controle de árvore do AOT. Os TreeNode métodos de AOTfirstChild e AOTnextSibling realizar a navegação. Como uma alternativa equivalente, a classe X++ AOTiterator é projetada para navegar no controle de árvore da AOT. Um nó de classe é o pai sobre vários nós de método. As AOTiterator etapas através de nós filho, retornando cada um como outra TreeNode instância. Recursos adicionais os TreeNode métodos nomeados AOTparent e AOTprevious.
TreeNode .AOTgetProperty TreeNode .AOTgetProperties TreeNode .AOTname PropertyInfo Em X++, o AOTgetProperties método retorna uma cadeia de caracteres longa que contém pares nome-valor para todas as propriedades do TreeNode. O AOTname método retorna uma cadeia de caracteres que contém apenas o valor para a propriedade name.
TreeNode .AOTsave TreeNode .AOTinsert System .Reflection .Emit (namespace de classes) O AOTsave método aplica alterações de um TreeNode objeto em seu código X++ para o AOT, e as alterações são persistentes. Para obter um exemplo de código grande, consulte Método TreeNode.AOTsave.

Comparação: Classes sobre E/S de arquivo

Há várias classes que executam operações de entrada e saída de arquivo (IO). No .NET Framework que é usado em C#, as contrapartes para essas classes residem no System.IO namespace.

A tabela a System.IO seguir lista várias classes do .NET Framework para C# que estão no namespace. Cada linha na tabela mostra a classe X++ ou o método que melhor corresponde à classe .NET Framework.

X++ C# Comments
BinaryIo FileStream BinaryReader BinaryWriter Classes X++ como BinaryIo essa se estendem da classe Io abstrata servem como um fluxo, e eles também servem como um leitor e gravador para esse fluxo. Em C#, o fluxo é uma classe separada da classe que tem métodos de leitura e gravação mais específicos.
TextBuffer MemoryStream Essas classes contêm um buffer na memória, e alguns dos métodos tratam o buffer como se fosse um arquivo no disco rígido.
WINAPI::createDirectory WINAPI::folderExists WINAPI::removeDirectory Directory DirectoryInfo Path X++ pode usar métodos estáticos na classe para muitas funções básicas do WINAPI sistema operacional que envolvem diretórios.
WINAPI::getDriveType DriveInfo DriveType Essas classes e métodos são usados para obter informações relacionadas à unidade.
WINAPI::copyFile WINAPI::createFile WINAPI::d eleteFile WINAPI::fileExists File FileAttributes FileInfo X++ pode usar métodos estáticos na classe para muitas funções básicas do WINAPI sistema operacional que envolvem arquivos.
CommaIo Comma7Io (Nenhuma classe correspondente.) Essas classes X++ podem gerar arquivos que o Microsoft Excel pode importar. No X++, está disponível uma referência da biblioteca EPPlus para interação adicional com o Excel.
AsciiIo TextIo FileStream TextReader TextWriter Essas classes usam páginas de código diferentes.
Io Stream StreamReader StreamWriter FileStream Estas são frequentemente usadas como classes base que outras classes estendem.
CodeAccessPermission FileIoPermission System.Security .CodeAccessPermission O namespace System.Security.Permissions inclui as seguintes classes:
  • CodeAccessSecurityAttribute
  • FileIOPermissionAttribute
  • FileIOPermission
  • FileIOPermissionAccess
Os conceitos e métodos de assert, demande revertAssert aplicam-se a ambas as línguas. No entanto, os deny métodos e revertDeny que estão disponíveis em C# não estão disponíveis no X++.

X++, Comparação ANSI SQL: SQL Select

No X++, a sintaxe da instrução SQL select difere da especificação ANSI (American National Standards Institute).

Seleção de tabela única

A tabela a seguir lista as diferenças entre as instruções select de X++ SQL e ANSI SQL.

Característica X++ SQL ANSI SQL Comments
Nome da tabela na cláusula from . A cláusula from lista uma instância de buffer de registro que é declarada de uma tabela, como da CustTable tabela. A cláusula from lista um nome de tabela, não o nome de um buffer. O buffer de registro tem todos os métodos que a xRecordclasse tem no X++.
Seqüência de sintaxe da ordem por versus onde cláusulas. A ordem por cláusula deve aparecer antes da cláusula where . A cláusula order by deve aparecer após a cláusula de from ou join . O grupo por cláusula deve seguir as mesmas regras de posicionamento de sintaxe que a ordem por segue. A ordem por cláusula deve aparecer após a cláusula where . A cláusula where deve aparecer após a cláusula de from ou junte . Em X++ e ANSI SQL, as cláusulas from e join devem aparecer antes das cláusulas order by e where .
Negação da condição. O ponto de exclamação ('!') é usado para negação. A palavra-chave not é usada para negação. X++ não suporta a sintaxe !like. Em vez disso, você deve aplicar o ! operador a uma cláusula.
Caracteres curinga para o operador similar . 0 para muitos – Asterisk ('*')
Exatamente 1 – Ponto de interrogação ('?')
0 a muitos – Sinal de percentagem ('%')
Exatamente 1 – Underbar ('_')
Operadores lógicos na cláusula where . E – &&
Ou – ||
E – e
Ou – ou

Exemplo de código

O exemplo de código a seguir ilustra recursos na tabela anterior.

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*') &amp;&amp; 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
***/

Palavras-chave X++ SQL

As seguintes palavras-chave X++ SQL estão entre aquelas que não fazem parte do ANSI SQL:

  • Empresa cruzada
  • firstonly100
  • forçaliterais
  • forcenestedloop
  • ForçaEspaços Reservados
  • ForceSelectOrder
  • ValidTimeState

Cláusula de adesão

A tabela a seguir lista as diferenças sobre a palavra-chave join de X++ SQL e ANSI SQL.

Característica X++ SQL ANSI SQL Comments
Lista de colunas. As colunas na lista de colunas devem vir todas da tabela listada na cláusula from e não de qualquer tabela em uma cláusula de junção . As colunas na lista não podem ser qualificadas pelo nome da tabela. As colunas na lista de colunas podem vir de qualquer tabela nas cláusulas de oujunte . Ele ajuda outras pessoas a manter seu código quando você qualifica as colunas na lista com o nome da tabela. Para obter mais informações, consulte Selecionar instruções em campos.
Sintaxe da cláusula de junção . A cláusula de junção segue a cláusula where . A cláusula de junção segue uma tabela na cláusula from . No exemplo de código X++, o critério de junção é uma igualdade de SalesPoolId valores.
Palavra-chave interna . O modo de associação padrão é a junção interna. Não há uma palavra-chave interna . O modo de associação padrão é a junção interna. A palavra-chave interna está disponível para tornar o código explícito. A palavra-chave outer existe em X++ SQL e ANSI SQL.
Palavras-chave esquerda e direita . As palavras-chave esquerda e direita não estão disponíveis. Todas as junções são deixadas. As palavras-chave esquerda e direita estão disponíveis para modificar a palavra-chave junte . Sem comentários.
Operador de igualdade. O operador de sinal duplo igual ('==') é usado para testar a igualdade de dois valores. O operador de sinal de igual único ('=') é usado para testar a igualdade de dois valores. Sem comentários.

Exemplo de código

O exemplo de código a seguir ilustra a sintaxe de junção no 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);
    }
}

Campos agregados

A tabela a seguir lista algumas diferenças na forma como os campos agregados na lista de colunas selecionadas são referenciados entre X++ SQL e ANSI SQL. Campos agregados são aqueles que são derivados por funções como soma ou média.

Característica X++ SQL ANSI SQL Comments
Agregar alias de nome de campo. O valor agregado está no campo que foi agregado. Você pode usar a palavra-chave as para marcar um campo agregado com um alias de nome. O alias pode ser referenciado no código subsequente. Para obter mais informações, consulte Funções agregadas: diferenças entre X++ e SQL

Exemplo de código

No exemplo de código a seguir, a chamada para o método info ilustra a maneira de fazer referência a campos agregados (consulte 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.
***/

Outras diferenças

A tabela a seguir lista outras diferenças da instrução select entre o X++ SQL e o ANSI SQL.

Característica X++ SQL ANSI SQL Comments
A palavra-chave ter . Não há uma palavra-chave. A palavra-chave having permite especificar critérios de filtro para linhas que são geradas pelo grupo por cláusula. Sem comentários.
Resultados nulos. Em uma instrução while select, se a cláusula where filtrar todas as linhas, nenhuma linha de contagem especial será retornada para relatar isso. Em uma seleção, se a cláusula where filtrar todas as linhas, uma linha de contagem especial será retornada. O valor da contagem é 0. Sem comentários.
Cursores para navegar pelas linhas retornadas. A instrução while select fornece a funcionalidade do cursor. A alternativa é usar a próxima palavra-chave. Você pode declarar um cursor para fazer looping pelas linhas retornadas de uma instrução select .
Da cláusula. A palavra-chave from é opcional quando nenhuma coluna é listada e apenas uma tabela é referenciada. As duas opções de sintaxe a seguir são equivalentes:
select \* from tCustTable;
select tCustTable;
Uma instrução select não pode ser lida de uma tabela, a menos que a cláusula from seja usada. No X++ SQL, a instrução select simples preenche a variável de buffer da tabela com a primeira linha que foi retornada. Isso é ilustrado pelo seguinte fragmento de código:
select \* from tCustTable;
info(tCustTable.Name);