Usar instruções repetitivas

Concluído

Você pode usar instruções repetitivas quando desejar repetir a implementação de uma ou mais instruções. Os cinco tipos diferentes de instruções repetitivas que você pode usar são:

  • for-to-do

  • for-downto-do

  • foreach-in-do

  • while-do

  • repeat-until

Instrução For

Uma das instruções repetitivas mais usadas é a instrução for. Se você usar a instrução for, já deve saber quantas vezes a implementação das instruções será repetida.

No próximo exemplo, a instrução for é usada para um loop de cinco vezes. A variável intCount contará o número de vezes que você repetiu.

var
    intCount: Integer;
    total: Integer;
begin
    for intCount := 1 to 5 do
        total := total + 3;
end;

No exemplo a seguir, o número de loops é corrigido usando um número (como 5). Você também pode usar outra variável inteira em vez de um valor fixo. De qualquer maneira, a instrução for sabe, antecipadamente, quantos loops serão necessários.

var
    intCount: Integer;
    numberOfLoops: Integer;
    total: Integer;
begin
    numberOfLoops := 5;
    for intCount := 1 to numberOfLoops do
        total := total + 3;
end;

A instrução for só pode executar uma instrução. Se você quiser executar mais de uma instrução, precisará usar uma instrução composta com begin e end.

Instrução For downto

Com a instrução for, você está contando para cima, o que significa que a instrução for aumentará o valor da variável. Você também pode diminuir usando a instrução for downto, que conta para baixo.

Semelhante à instrução for, que só pode executar uma instrução, a instrução for downto só executa uma instrução. O próximo exemplo mostra a instrução composta que está sendo usada.

var
    intCount: Integer;
    totalSales: Integer;
    numberSales: Integer;
    sales: array[5] of Integer;
begin
    GetSales(sales);

    for intCount := 5 downto 1 do begin
        totalSales := totalSales + sales[intCount];
        numberSales := numberSales + 1;
    end;
end;

Instrução Foreach

A instrução foreach só pode ser usada em coleções Enumerable (List of e Dictionary of), e não pode ser usada com matrizes.

Com a instrução foreach, a variável receberá o valor de um determinado item nas coleções. Cada loop será atribuído ao próximo valor.

var
    stringList: List of [Text[20]];
    stringItem: Text[20];
begin
    foreach stringItem in stringList do
        Message(stringItem);
end;

Instrução While

A instrução while verifica primeiro se a condição é verdadeira antes de iniciar o loop. Se essa condição for verdadeira, ela continuará executando as instruções no seu bloco while.

Portanto, será possível que as instruções não sejam executadas se a condição não for true na primeira vez.

var
    index: Integer;
    totalSales: Integer;
    sales: array[5] of Integer;
begin
    GetSales(sales);

    while totalSales < 8 do begin
        index := index + 1;
        totalSales := totalSales + sales[index];
    end;
end;

Se você quiser executar várias instruções, precisará usar uma instrução composta.

Instrução Repeat until

A instrução while verifica primeiro se há uma condição válida antes de iniciar o loop, enquanto a instrução repeat until vai ser executada primeiro e, depois, verificar se há uma condição. Ela fará um loop até que a condição seja válida, o que significa que as instruções repeat until são, no mínimo, executadas uma vez. O loop continuará, se a condição não for válida.

A instrução repeat until é uma instrução única, e você coloca suas próprias instruções no bloco. Essa característica significa que você não precisará usar uma instrução composta se quiser executar várias instruções.

var
    index: Integer;
    totalSales: Integer;
    sales: array[5] of Integer;
begin
    GetSales(sales);

    repeat
        index := index + 1;
        totalSales := totalSales + sales[index];
    until totalSales >= 8;
end;

Geralmente, a instrução repeat until é usada quando você deseja executar um loop sobre um conjunto de registros. No próximo exemplo, você fará um loop sobre todas as linhas da tabela MyTable.

var
    myTable: Record MyTable;
begin
    myTable.FindSet();
    repeat
        myTable.Amount := 100;
    until myTable.Next() = 0;
end;

Instrução With

A instrução with às vezes é usada em combinação com uma instrução repetitiva, mas também pode ser usada de maneira autônoma. A finalidade da instrução with é reduzir o uso das suas variáveis de registro. Essa estrutura é ilustrada no exemplo a seguir, onde uma variável myTable é criada, e os campos na tabela são todos atribuídos com um valor.

var
    myTable: Record MyTable;
begin
    myTable."No." := 1;
    myTable.Amount := 100;
    myTable.Credits := 10;
    myTable."Document Type" := myTable."Document Type"::Invoice;
    myTable.Reason := myTable.Reason::Return;
    myTable.Refund := 100;
end;

Em vez de digitar novamente a palavra myTable, você pode usar a instrução with.

var
    myTable: Record MyTable;
begin
    with myTable do begin
        "No." := 1;
        Amount := 100;
        Credits := 10;
        "Document Type" := "Document Type"::Invoice;
        Reason := Reason::Return;
        Refund := 100;
    end;
end;

Preterir as instruções with explícitas e implícitas

O modelo de extensibilidade e a linguagem de programação AL são sucessores da linguagem C/AL. E até agora, a instrução with era permitida em AL.

Usar a instrução with pode dificultar a leitura do código. Ele também pode impedir que o código em Business Central seja atualizado sem alterações no código ou ainda pior - atualizado, mas com comportamento alterado.

Nós consideramos dois tipos diferentes de instruções with: o tipo explícito com uso de palavra-chave e o tipo implícito que não é expresso diretamente no código. As próximas seções descrevem cada uma dessas instruções.

Instruções with explícitas

No Business Central Online, seu código é recompilado quando as versões da plataforma e do aplicativo são atualizadas. A recompilação garante que ela funcione e regenera os artefatos de runtime para que correspondam à nova plataforma. Não são permitidas alterações da falha sem o devido aviso, mas o uso da instrução with impossibilita, como a Microsoft, fazer alterações aditivas de modo completamente sem falha. Esse problema não é isolado das alterações feitas pela Microsoft. Qualquer alteração aditiva tem o potencial de falhar uma instrução with no código de consumo.

O exemplo a seguir ilustra o código escrito com a instrução with, chamado neste contexto de instrução with explícita:


codeunit 50140 MyCodeunit
{
    procedure DoStuff()
    var
        Customer: Record Customer;
    begin
        with Customer do begin
            // Do some work on the Customer record.
            Name := 'Foo';

            if IsDirty() then 
                Modify();
        end;
    end; 

    local procedure IsDirty(): Boolean;
    begin
        exit(false);
    end;
}

O procedimento DoStuff() processa o trabalho no registro de Customer e chama um procedimento local IsDirty() para verificar se deve ou não atualizar o registro. Observando o código anterior, parece que ele não faz nada, já que IsDirty() retorna falso, supondo que a chamada IsDirty() (linha 11) esteja de fato chamando o procedimento IsDirty() local.

Pesquisas de símbolos

Considerando novamente o exemplo de código anterior, o que aconteceria com esse código se IsDirty fosse adicionado ao aplicativo base entre duas liberações? Para entender isso, precisamos examinar como os compiladores transformam a sintaxe em símbolos. Quando o compilador AL atende à chamada IsDirty, ele deve associar o nome da sintaxe a um símbolo do procedimento.

Quando o compilador AL pesquisa o símbolo IsDirty() no exemplo anterior, ele pesquisa na seguinte ordem:

1 – tabela Customer

  • Membros definidos pelo usuário na tabela Customer e nas extensões da tabela Customer

  • Membros definidos pela plataforma, por exemplo, FindFirst() ou Modify()

2 – Codeunit MyCodeunit

  • Membros definidos pelo usuário, por exemplo, IsDirty()
  • Membros definidos pela plataforma

3 – Membros definidos globalmente

Quando a pesquisa por IsDirty encontrar o nome IsDirty pela primeira vez, ela não prosseguirá para próximo grupo de nível superior. Isso significa que, se um procedimento chamado IsDirty for introduzido na tabela Customer, (plataforma ou aplicativo), esse procedimento será encontrado no lugar do procedimento em MyCodeunit.

A solução para o with explícito é parar de usá-lo. O uso da instrução with pode tornar seu código vulnerável a alterações de upstream. O exemplo a seguir ilustra como reescrever o exemplo usando a instrução with explícita.


// Safe version
codeunit 50140 MyCodeunit
{
    procedure DoStuff()
    var
        Customer: Record Customer;
    begin
        // Do some work on the Customer record.
        Customer.Name := 'Foo';

        if IsDirty() then 
            Customer.Modify();
    end; 

    local procedure IsDirty(): Boolean;
    begin
        exit(false);
    end;
}

Instrução with implícita

O with implícito é inserido automaticamente pelo compilador em determinadas situações. As seções a seguir descrevem como isso funciona nas codeunits e nas páginas.

Codeunits

Quando uma codeunit tem a propriedade TableNo definida, o código dentro do gatilho OnRun é colocado entre with implícito. Isso é indicado pelos comentários no exemplo de código abaixo.


codeunit 50140 MyCodeunit
{
    TableNo = Customer;

    trigger OnRun()
    begin
        // with Rec do begin
        SetRange("No.", '10000', '20000');
        if Find() then
            repeat
            until Next() = 0;

        if IsDirty() then
            Error('Something is not clean');
        // end;
    end;

    local procedure IsDirty(): Boolean;
    begin
        exit(false);
    end;
}

De forma semelhante à Instrução with explícita, o código parece chamar o método local IsDirty. Mas, dependendo da tabela Customer, extensões para a tabela Customer e métodos internos, esse pode não ser o caso. Se qualquer um deles implementar um método IsDirty com uma assinatura idêntica que retorne verdadeiro, o exemplo acima falhará com um erro. Se um método IsDirty com uma assinatura diferente for implementado, esse código não será compilado e não poderá ser atualizado.

Páginas

As páginas nas tabelas têm o mesmo tipo de with implícito, mas envolvendo o objeto inteiro. Em qualquer lugar dentro do objeto de página, os campos e os métodos das tabelas de origem estão diretamente disponíveis sem nenhum prefixo.


page 50143 ImplicitWith
{
    SourceTable = Customer;

    layout
    {
        area(Content)
        {
            field("No."; "No.") { }
            field(Name; Name)
            {
                trigger OnValidate()
                begin
                    Name := 'test';
                end;
            }
        }
    }

    trigger OnInit()
    begin
        if IsDirty() then Insert()
    end;

    local procedure IsDirty(): Boolean
    begin
        exit(Name <> '');
    end;
}

Nas páginas, não é apenas o código nos gatilhos e procedimentos que está incluído no with implícito no registro de origem, as expressões de origem dos campos também são abordadas.

Com ou sem with: isso não é uma questão

Neste repositório GitHub, você pode encontrar mais exemplos e códigos: BCTech/samples/WithOrWithout/

Instrução break

Se desejar interromper a execução de um loop, poderá usar a instrução break.

var
    intCount: Integer;
    total: Integer;
begin
    for intCount := 1 to 5 do begin
        if (total > 8) then
            break;

        total := total + 3;
    end;
end;