Usar instrucciones repetitivas

Completado

Puede usar instrucciones repetitivas cuando quiera repetir la implementación de una o más instrucciones. Los cinco tipos diferentes de instrucciones repetitivas que se pueden usar son:

  • for-to-do

  • for-downto-do

  • foreach-in-do

  • while-do

  • repeat-until

Instrucción for

Una de las instrucciones repetitivas más utilizadas es la instrucción for. Si usa la instrucción for, ya debería saber cuántas veces va a repetir la implementación de instrucciones.

En el siguiente ejemplo, la instrucción for se utiliza para hacer un bucle cinco veces. La variable intCount cuenta el número de veces que se ha hecho el bucle.

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

En el siguiente ejemplo, el número de bucles se fija mediante un número (como 5). También puede usar otra variable integral en lugar de un valor fijo. En cualquier caso, la instrucción for sabe con antelación cuántas veces tendrá que hacer el bucle.

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

La instrucción for solo puede ejecutar una instrucción. Si quiere ejecutar más de una instrucción, debe usar una instrucción compuesta con begin y end.

Instrucción for downto

Con la instrucción for, está contando hacia arriba, es decir, la instrucción for aumenta el valor de la variable. También puede disminuir utilizando la instrucción for downto, que cuenta hacia abajo.

De modo similar a la instrucción for, que solo puede ejecutar una instrucción, la instrucción for downto solo ejecuta una instrucción. En el siguiente ejemplo se muestra el uso de la instrucción compuesta.

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;

Instrucción foreach

La instrucción foreach solo se puede usar en colecciones del tipo Enumerable (List of y Dictionary of), y no se puede usar con matrices.

Con cada instrucción foreach, la variable obtendrá el valor de un artículo determinado de las colecciones. A todos los bucles se les asigna el siguiente valor.

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

Instrucción while

La instrucción while comprueba primero si la condición es true antes de iniciar el bucle. Si la condición es true, sigue ejecutando las instrucciones en el bloque de while.

Por lo tanto, es posible que las instrucciones no se ejecuten si la condición no es true la primera 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;

Si quiere ejecutar varias instrucciones, debe usar una instrucción compuesta.

Instrucción repetir hasta

La instrucción while comprueba primero si existe una condición válida antes de iniciar el bucle, mientras que la instrucción repeat until se ejecuta primero y después comprueba una condición. Se repite en bucle hasta que la condición es válida, lo que significa que las instrucciones repeat until se ejecutan al menos una vez. El bucle continuará siempre que la condición no sea válida.

La instrucción repeat until es una sola instrucción, y usted pone sus propias instrucciones dentro del bloque. Esto implica que no tiene que usar una instrucción compuesta si quiere ejecutar varias instrucciones.

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;

La instrucción repeat until se suele usar cuando se quiere realizar un bucle por un conjunto de registros. En el siguiente ejemplo, realizará un bucle por todas las filas de la tabla MyTable.

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

Instrucción with

La instrucción with se usa a veces en combinación con una instrucción repetitiva, pero también se puede usar de forma independiente. El propósito de la instrucción with es reducir el uso de las variables del registro. Esta estructura se ilustra en el siguiente ejemplo, donde se crea una variable myTable y se asigna un valor a todos los campos de la tabla.

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;

En lugar de volver a escribir la palabra myTable, puede usar la instrucción 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;

Depreciación de instrucciones with explícitas e implícitas

El modelo de extensibilidad y el lenguaje de programación AL sustituyen al lenguaje C/AL. Hasta ahora, la instrucción with ha sido compatible en AL.

El uso de la instrucción with podría dificultar la lectura del código. También puede evitar que el código de Business Central se actualice sin cambios en el código o que se actualice con un comportamiento cambiado, lo que es peor.

Hay dos tipos de instrucciones with: el tipo with explícito, con la palabra clave, y el with implícito, que no se expresa directamente en el código. En las siguientes secciones, se describen estas instrucciones.

Instrucciones with explícitas

En Business Central Online, el código se vuelve a compilar cuando se actualizan las versiones de la plataforma y la aplicación. La recompilación garantiza que está funcionando y regenera los artefactos de runtime para que coincidan con la nueva plataforma. No está permitido hacer cambios importantes sin la debida advertencia, pero el uso de la instrucción with hace que Microsoft no pueda ni siquiera añadir cosas de un modo intrascendente. Este problema no se limita a los cambios realizados por Microsoft; cualquier cambio aditivo puede romper una instrucción with en el código de consumo.

En el siguiente ejemplo se ilustra el código escrito usando la instrucción with; en este contexto se denomina instrucción 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;
}

Los procesos del procedimiento DoStuff() funcionan en el registro Customer, y este procedimiento llama a un procedimiento local IsDirty() para verificar si se actualiza el registro o no. Al observar el código anterior, parece que no haya nada, ya que IsDirty() devuelve falso, suponiendo que la llamada IsDirty() (línea 11) esté llamando al procedimiento local IsDirty().

Búsquedas de símbolos

Pensemos de nuevo en el ejemplo de código anterior: ¿qué pasaría con ese código si IsDirty se agregara a la aplicación base entre dos versiones? Para entenderlo, debemos observar cómo los compiladores convierten la sintaxis en símbolos. Cuando el compilador AL cumple con la llamada IsDirty, se debe vincular el nombre de la sintaxis a un símbolo de procedimiento.

Cuando el compilador AL busca el símbolo IsDirty() en el ejemplo anterior, buscará en el siguiente orden:

1- Tabla Customer

  • Miembros definidos por el usuario en la tabla Customer y extensiones de la tabla Customer

  • Miembros definidos por la plataforma, por ejemplo, FindFirst() o Modify()

2- Codeunit MyCodeunit

  • Miembros definidos por el usuario, por ejemplo, IsDirty()
  • Miembros definidos por la plataforma

3- Miembros definidos globalmente

La primera vez que la búsqueda de IsDirty encuentra el nombre IsDirty, no continuará con el siguiente grupo de nivel superior. Eso significa que si se introduce un procedimiento denominado IsDirty en la tabla Cliente (plataforma o aplicación), ese procedimiento se encontrará en lugar del procedimiento en MyCodeunit.

La solución para el with explícito es dejar de usarlo. El uso de la instrucción with puede hacer que su código sea vulnerable a los cambios anteriores. En el siguiente ejemplo se ilustra cómo reescribir la muestra usando La instrucción 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;
}

Instrucción with implícita

El with implícito es inyectado automáticamente por el compilador en determinadas situaciones. Las siguientes secciones describen el funcionamiento de esto en codeunits y páginas.

Codeunits

Cuando una codeunit tiene establecida la propiedad TableNo, hay un with implícito alrededor del código dentro del desencadenador OnRun. Esto se indica con los comentarios en el ejemplo de código siguiente.


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

Como ocurre con la instrucción with explícita, parece que el código llama al método local IsDirty. Sin embargo, en función de la tabla Customer, las extensiones de la tabla y los métodos integrados, es posible que ese no sea el caso. Si alguna de estas implementa un método IsDirty con una firma idéntica que devuelva true, el ejemplo anterior generará un error. Si se implementa un método IsDirty con una firma diferente, el código no se compilará ni se actualizará.

Páginas

Las páginas de las tablas tienen el mismo tipo de with implícito, pero alrededor de todo el objeto. En cualquier lugar dentro del objeto de la página, los campos y métodos de las tablas de origen están disponibles directamente sin ningún prefijo.


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

En las páginas, no solo abarca el código de los desencadenadores y los procedimientos con el with implícito en el registro de origen; también se cubren las expresiones de origen para los campos.

Con o sin, esa no es la cuestión

Aquí, en este repositorio de GitHub, puede encontrar más ejemplos y código: BCTech/samples/WithOrWithout/

Instrucción break

Si quiere detener la ejecución de un bucle, puede usar la instrucción break.

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

        total := total + 3;
    end;
end;