X++ sammansatta datatyper

Anmärkning

Intressegrupper för communityn har nu flyttat från Yammer till Microsoft Viva Engage. Om du vill gå med i en Viva Engage-community och delta i de senaste diskussionerna fyller du i formuläret Begär åtkomst till Finance and Operations Viva Engage Community och väljer den community som du vill ansluta till.

I den här artikeln beskrivs sammansatta datatyper i X++. De sammansatta datatyperna i X++ är matriser, containrar, klasser som datatyper, ombud som datatyper och tabeller som datatyper.

Array

En matris är en variabel som innehåller en lista över objekt som har samma datatyp. Elementen i en matris används med hjälp av heltalsindex. Du använder en separat instruktion för att initiera varje element i en matris. När du använder en containerdatatyp eller ett matrisobjekt för att skapa en samling kan du initiera flera element med hjälp av en enda instruktion. Som standard har alla objekt i en matris standardvärdet för datatypen i matrisen. Det finns tre typer av matriser: dynamiska matriser, matriser med fast längd och delvis på diskmatriser.

  • Dynamiska matriser – Dessa matriser deklareras med hjälp av ett tomt matrisalternativ. Med andra ord har de bara hakparenteser ([]).
  • Matriser med fast längd – Dessa matriser kan innehålla det antal objekt som anges i deklarationen. Matriser med fast längd deklareras som dynamiska matriser, men ett längdalternativ ingår i hakparenteserna.
  • Delvis på diskmatriser – Dessa matriser deklareras som antingen dynamiska matriser eller matriser med fast längd som har ett extra alternativ som deklarerar hur många objekt som ska lagras i minnet. De andra objekten lagras på disken och läses in automatiskt när de refereras.

X++ stöder endast endimensionella matriser. Du kan dock efterlikna beteendet för flera matrisindex. (Mer information finns i avsnittet Flera matrisindex ). Variabler i objekt och tabeller kan deklareras som matriser. Den här funktionen används till exempel i adressrader i standardprogrammet. Med en matrissamlingsklass kan du lagra objekt i en matris.

Matrisindex börjar vid 1. Det första objektet i matrisen refereras till som [1], det andra objektet refereras till som [2] och så vidare. Följande syntax används för att komma åt ett matriselement: ArrayItemReference = ArrayVariable [ Index ]. I den här syntaxen är ArrayVariable matrisens identifierare och Index är antalet matriselement. Index kan vara ett heltalsuttryck. Objekt noll [0] används för att rensa matrisen. Om ett värde tilldelas index 0 i en matris återställs alla element i matrisen till standardvärdet.

En tilldelning av en hel matris till en annan utförs med referens.

Matrisexempel

public void ArrayMethod()
{
    int myArray[10]; // Fixed-length array with 10 integers.
    myArray[4] = 1; // Accessing the 4th element in the array.
    myArray[0] = 0; // Resets all elements in intArray.

    // Dynamic array of integers.
    int intArray[];

    // Dynamic array of variables of type Datatype.
    //Datatype arrayVariable[];

    // Fixed-length arrays.
    boolean boolArray[100]; // Fixed-length array of booleans with 100 items.

    // Two examples of Partly On Disk Arrays.
    // Dynamic integer array with only 100 elements in memory.
    int arrayVariable [ ,100];
    // Fixed-length string array with 1000 elements, and only 200 in memory.
    str arrayVariable2 [1000,200];

    // A dynamic array of integers.
    int i[];
    // A fixed-length real array with 100 elements.
    real r[100];
    // A dynamic array of dates with only 10 elements in memory.
    date d[,10];
    // A fixed length array of NoYes variables with 100 elements and 10 in memory.
    NoYes ny[100,10];
}

Flera matrisindex

Med vissa språk, till exempel C++ och C#, kan du deklarera matriser som har fler än ett index. Med andra ord kan du definiera "matriser med matriser". I X++kan du inte direkt skapa flera matrisindex eftersom endast endimensionella matriser stöds. Du kan dock implementera flera index med hjälp av den metod som beskrivs i det här avsnittet. Du vill till exempel deklarera en matris som har två dimensioner för att innehålla ett belopp som intjänas efter land/region efter dimension. Det finns 10 länder/regioner och tre dimensioner. I C++ och C#deklarerar du följande matris.

// This is C# or C++ code, not X++ code.
long earning[10, 3];

X++ stöder dock inte den här deklarationen. I stället kan du definiera en endimensionell matris där antalet element är produkten av elementen i varje dimension. Här är ett exempel:

public void MultipleArrayMethod()
{
    // Step 1: define a one-dimensional array with the number
    // of elements that is the product of the elements in each dimension.
    real earnings[10*3];

    // Step 2: to refer to a specific element, such as earnings[i,j], write the following:
    // declare i and j (maybe) and assign the value to something
    int i = 1;
    int j = 2;
    real element = earnings[(i-1)*3 + j];
}

// This can be written into a macro like this:
#localmacro.earningIndex
(%1-1)*3+%2
#endmacro

public void CallTheMacro()
{
    // Next, call the specific element within the macro like this:
    int i = 1;
    int j = 2;
    real element = earnings[#earningIndex(i,j)];

    // The previous scheme can be extended to any number of dimensions.
    // The element a[i1, i2, ..., ik] can be accessed by computing the
    // offset into an array containing (d1*d2*...*dk) elements.
    //(i1 - 1)*d2*d3*..*dk +
    //(i2 - 1)*d3*d4*...*dk + .... +
    //(ik-1 -1)*dk +
    //(ik-1)
}

Behållare

Ett containerobjekt är en dynamisk lista över objekt som innehåller primitiva datatyper eller sammansatta datatyper. En container är användbar när du måste skicka olika typer av värden mellan klient- och servernivåerna. Men om du planerar att lägga till flera gånger i en lista i en loop är en container inte ett bra val. Containrar är lämpligast för processer som inte innebär alltför stora ändringar av containerns storlek eller innehåll. När en container genomgår alltför stora datatillägg kan den övergripande systemprestandan minska eftersom containerdata måste kopieras upprepade gånger och nytt utrymme måste allokeras upprepade gånger.

En container är inte en klass. En container innehåller en ordnad sekvens med primitiva värden eller andra containrar. På grund av flexibiliteten hos anytype erbjuder en container ett bra sätt att lagra värden av olika typer tillsammans. En container kan lagras i databasen. En container är en av de kolumntyper som du kan välja när du använder Application Explorer för att lägga till en kolumn i en tabell. En container liknar en matris eller samlingar, till exempel list- eller stackklasserna . Du kan dock aldrig ändra storlek eller innehåll för en container när containern har skapats.

X++-instruktioner som verkar ändra en container skapar internt en ny container och kopierar värden efter behov. Även en tilldelning av en container till en annan containervariabel skapar en ny kopia av containern. Alla dessa åtgärder kan påverka prestanda. I de funktioner som ger åtkomst till en container (till exempel conPeek) är containern 1-baserad, inte 0-baserad. Indexering är 1-baserad för matriser. Standardvärdet för en container är tomt. Containern innehåller inga värden. Vissa instruktioner som använder containrar kan verka ändra en container, men i systemet ändras aldrig containrar. I stället kombineras data från den ursprungliga containern med data från kommandot för att skapa en ny container. Du kan skapa en ny container med någon av följande funktioner: conDel, conIns eller conPoke.

Dessutom har klassen Global statiska metoder för hantering av containrar. Dessa metoder omfattar con2ArraySource, con2Buf, con2List, con2Str, containerFromXmlNode, conView och str2Con. Det finns flera inbyggda funktioner för hantering av en container, till exempel conIns och conPeek. Funktionen X++ conPeek returnerar en anytype-typ . Därför är det enklare att läsa värdena från en container när du inte känner till typen av varje värde. En anytype kan tilldelas till valfri X++-värdetyp, förutsatt att värdet kan konverteras. Koden är lättare att läsa när den undviker explicita datatypskonverteringar. Tilldela därför värden från en container till samma datatyp som användes för att placera värdet i containern. Du får inte tilldela en container till en anytype eftersom systemet kanske inte kan fastställa rätt konverteringar. I dessa fall kan oväntat beteende eller fel inträffa.

Jämföra container med andra alternativ

Containertypen liknar andra konstruktioner, till exempel matriser och samlingsklasser, till exempel Lista och Stack. Skillnaden mellan en container och Lista är att en instans av klassen List är föränderlig. Ett listobjekt allokerar först mer utrymme än vad dess data förbrukar. När data läggs till fylls sedan utrymmet. Det här beteendet är effektivare än att allokera mer utrymme varje gång ett element läggs till. En uppdatering av en lista utför snabbare än liknande åtgärder på en container.

När du skapar ett listobjekt avgör du vilken typ av data som listobjektet kan lagra. Den här begränsningen är mindre flexibel för en lista än för en container. Du kan dock lagra objekt i en lista, medan en container endast kan lagra värdetyper. Skillnaden mellan en container och en matris är att en matris endast kan innehålla objekt av den deklarerade typen. Du kan allokera minnesutrymme för en matris och fylla det utrymmet med värden senare. Du kan till exempel fylla i värden i en loop. Det här beteendet är effektivt och fungerar bra. När du vill skapa en ny container genom att lägga till nya data kan du använda antingen operatorn += eller conIns-funktionen . Operatorn += är det snabbare alternativet. Använd endast conIns-funktionen när du vill lägga till nya data före det sista indexet för ursprungliga data.

Du kan inte lagra objektreferenser i containrar. När kompilatorn identifierar ett försök att lagra en objektreferens i en container, utfärdar den ett felmeddelande. Om typen av element som läggs till i containern är anytype kan kompilatorn inte avgöra om värdet är en referenstyp. I det här fallet tillåter kompilatorn försöket. Även om kompilatorn inte diagnostiserar koden som felaktig utlöses ett fel vid körning.

Containerexempel

public void ContainerExample()
{
    // First, declare the variables you are using.
    container myContainer;
    container myContainer4;
    container myContainer5;
    // Three ways to declare a container.
    myContainer = [1];
    myContainer += [2];
    myContainer4 = myContainer5;

    // Declare a container.
    container cr3;

    // Assign a literal container to a container variable.
    cr3 = [22, "blue"];

    // Declare and assign a container.
    container cr2 = [1, "blue", true];

    // Mimic container modification (implicitly creates a copy).
    cr3 += [16, strMyColorString];
    cr3 = conIns(cr3, 1, 3.14);
    cr3 = conPoke(cr3, 2, "violet");

    // Assignment of a container (implicitly creates a copy).
    cr2 = cr3;

    // Read a value from the container.
    str  myStr = conPeek(cr2, 1);

    // One statement that does multiple assignments from a container.
    str myStr;
    int myInt;
    container cr4 = ["Hello", 22, 20\07\1988];
    [myStr, myInt] = cr4; // "Hello", 22

    // Example of applying the = operator to a container. The example
    // initializes myContainer2 and myContainer33.
    myContainer2 = [2, "apple"];

    // Next, you make a copy of myContainer33 and assign the copy to myContainer2.
    myContainer33 = [33, "grape"];
    myContainer2 = myContainer33;  // The container that myContainer2 had been holding is no longer available and cannot be recovered.
    // An example of building a new container by
    // assigning a new value to myContainer33 through the += operator.
    myContainer33 += [34, "banana"];
}

// Container example. In this example, variable2 and variable33 hold different containers.
static void JobC(Args _args)
{
    container variable2, variable33;
    variable2 += [98];
    variable33 = variable2;
    variable2 += [97];
}

// List class example. In this example, variable2 and variable33 refer to the same List object.
static void JobL(Args _args)
{
    List variable2,variable33;
    variable2 = new List(Types::Integer);
    variable2.addEnd(98);
    variable33 = variable2;
    variable2.addEnd(97);
}

// The automatic type conversion by anytype also applies to the special syntax for making multiple
// assignments from a container in one statement. This is shown in the following code example,
// which assigns a str to an int, and an int to a str.
static void JobContainerMultiAssignmentUsesAnytype(Args _args)
{
    container con2;
    int int4;
    str str7;
    con2 = ["11", 222];
    [int4, str7] = con2;
    info(strfmt("int4==11==(%1), str7==222==(%2)", int4, str7));
}

/***  Output:
Message (10:36:22 am)
int4==11==(11), str7==222==(222)
***/

static void UseQuery()
{
    // An example of how the compiler diagnoses attempts to store object in containers
    container c = [new Query()];   // This statement will cause the error message shown below.
    /*** Instance of type 'Query' cannot be added to a container. ***/

    // An example of a code that won't cause an error message, but will
    // cause an error message to be thrown at runtime.
    anytype a = new Query();
    container d = [a];
}

Klasser som datatyper

En klass är en typdefinition som beskriver både variabler och metoder för instanser av klassen. (Instanserna av en klass kallas även objekt.) En klass är bara en definition för objekt och alla objekt är null när de deklareras. I Application Explorer är varje programklass under noden Klasser en datatyp. Du kan deklarera variabler av dessa typer i koden. Du kan skapa instanser av en klass och tilldela instanserna till variabler.

Klasser kan kapslas i källkod. Kapslade klasser är endast tillgängliga i formulär (till exempel en klass som utökar FormRun) och används för att representera kontroller, datakällor eller datafält. En attributdekoration, till exempel attributdekorationen för en klass eller en metod, kan utelämna suffixet för attributnamnet om suffixet är Attribut. Därför tillåter X++ [MyFavorite] i stället för att kräva [MyFavoriteAttribute]. Dessutom tillämpas attribut nu på hanterare av ombud och metoder för att mappa hanterare till dessa mål.

I AX 2012 och tidigare versioner kan du ange en metod som ska köras på antingen klienten eller servern. I ekonomi- och driftsprogram körs dock all kompilerad X++-kod som .NET Common Intermediate Language (CIL) på servern. Det finns inte längre någon kod som utvärderas på klientplatsen eller i webbläsaren. Därför ignoreras nu klient - och servernyckelorden . Även om dessa nyckelord inte orsakar ett kompileringsfel om de används bör de inte användas i någon ny kod.

Privata och skyddade medlemsvariabler

Tidigare skyddades alla medlemsvariabler som definierades i en klass. Nu kan du göra synligheten för medlemsvariabler explicit genom att lägga till privata, skyddade och offentliga nyckelord. Tolkningen av dessa modifierare är uppenbar och är anpassad till semantiken för metoder:

  • private – Medlemsvariabeln kan endast användas i den klass där den definieras.
  • protected – Medlemsvariabeln kan användas i klassen där den definieras och alla underklasser i den klassen.
  • public – Medlemsvariabeln kan användas var som helst. Den visas utanför gränserna för klasshierarkin där den definieras.

Som standard skyddas fortfarande medlemsvariabler som inte är prydda med en explicit modifierare. Men som bästa praxis bör du uttryckligen ange synligheten. Som vi beskrev tidigare, när en medlemsvariabel definieras som offentlig, kan den nås utanför den klass där den definieras. I det här fallet måste du ange en kvalificerare som anger det objekt som är värd för variabeln. Om du vill ange kvalificeraren använder du punkt notationen, precis som för metodanrop.

I följande exempel används field1 med hjälp av den explicita kvalificeraren . I det här fallet kanske det inte är en bra idé att göra en medlemsvariabel offentlig, eftersom den metoden exponerar klassens interna arbete för sina konsumenter och därför skapar ett starkt beroende mellan klassimplementeringen och dess konsumenter. Du bör alltid försöka att bara vara beroende av ett kontrakt, inte en implementering.

public class AnotherClass3
{
    int field1;
    str field2;
    void new()
    {
        this.field1 = 1;   // Explicit object designated.
        field2 = "Banana";  // 'this' assumed, as usual.
    }
}

Statiska konstruktorer och statiska fält

Statiska fält är fält som deklareras med hjälp av det statiska nyckelordet. Konceptuellt gäller statiska fält för klassen, inte för instanser av klassen. Statiska konstruktorer kommer garanterat att köras innan några statiska anrop eller instansanrop görs till klassen. Körningen av den statiska konstruktorn är relativ till användarens session. Du anropar aldrig den statiska konstruktorn explicit. I stället genererar kompilatorn kod för att se till att konstruktorn anropas exakt en gång, innan någon annan metod i klassen anropas. En statisk konstruktor används för att initiera statiska data eller utföra en åtgärd som bara måste utföras en gång. Du kan inte ange parametrar för den statiska konstruktorn och den måste markeras med det statiska nyckelordet.

// An example of how a singleton (call instance in the example below)
// can be created using the static constructor.
public class Singleton
{
    private static Singleton instance;
    private void new()
    {
    }
    static void TypeNew()    // This is the static constructor.
    {
        instance = new Singleton();
    }

    public static Singleton Instance()
    {
        return Singleton::instance;
    }
}

// The singleton ensures that only one instance of the class
// will be called, which is consumed by the following.
{
    // Your code here.
    Singleton i = Singleton::Instance();
}

Klasselement i Application Explorer

Under de flesta klassnoder i Application Explorer finns det två särskilda noder: en classDeclaration-nod och en ny nod. En classDeclaration innehåller alltid nyckelordet X++ -klass . Ytterligare nyckelord, till exempel utökar, kan inkluderas för att ändra klassen. Den här noden kan också innehålla deklarationer av medlemsvariabler.

I följande exempel är variablerna m_priority och m_rectangle medlemmar i klassen.

// An example of a classDeclaration.
public class YourDerivedClass extends YourBaseClass
{
    int m_priority;
    Rectangle m_rectangle;
    void new(int _length, int _width)
    {
        this.m_rectangle = new Rectangle(_length, _width);
    }
}

En ny operator innehåller logik som körs när den nya operatorn används för att skapa en instans av klassen. Logiken i den nya metoden kan konstruera ett objekt och tilldela objektet till en variabel som deklareras i classDeclaration. Varje klass kan bara ha en ny metod. I den nya metoden bör du dock ofta anropa den nya metoden för basklassen. Anropa super()för att anropa den nya metoden för basklassen.

I följande exempel visas den nya metoden för klassen YourDerivedClass i föregående classDeclaration-exempel . I den här nya metoden konstruerar koden en instans av klassen Rektangel . Instansen tilldelas variabeln m_rectangle . Det här nyckelordet som används i exemplet är valfritt, men om du inkluderar det kan IntelliSense vara mer användbart.

// An example of the new method from the previous classDeclaration example.
void new(int _length, int _width)
{
    this.m_rectangle = new Rectangle(_length, _width);
}

Skräpinsamling

Så småningom under körningen har de flesta objekt inte längre någon variabel som pekar på dem. Systemet söker efter dessa objekt och raderar dem från minnet. Minnesutrymmet blir sedan tillgängligt för andra användningsområden. Klassen Object har en metod med namnet finalize. Men metoden för att slutföra är inte en destruktor. Körningen anropar aldrig metoden finalize , även när ett objekt samlas in som skräp.

Systemklasser

I Application Explorer finns en lista över kernelklasser ellersystemklasser under >. Systemklasser skrivs inte i X++, och du kan inte se deras källkod. Du kan inte lägga till systemklasser. Systemklasser har vanligtvis en ny metod, men de har ingen classDeclaration-nod . Varje programklass utökar implicit objektsystemklassen . Vissa systemklasser utökas av en programklass som har ett liknande namn. Till exempel utökas xClassFactory av ClassFactory. I dessa fall bör du inte använda systemklassen. Mer information finns i "Ersätt programklasser för systemklasser" i Klasser och metoder.

Tilläggsmetoder

Med funktionen tilläggsmetod kan du lägga till tilläggsmetoder i en målklass genom att skriva metoderna i en separat tilläggsklass. Följande regler gäller:

  • Tilläggsklassen måste vara statisk.
  • Namnet på tilläggsklassen måste sluta med suffixet med tio tecken _Extension, men det finns ingen begränsning för den del av namnet som föregår suffixet.
  • Varje tilläggsmetod i tilläggsklassen måste deklareras som offentlig statisk.
  • Den första parametern i varje tilläggsmetod är den typ som tilläggsmetoden utökar. Men när tilläggsmetoden anropas får anroparen inte skicka in något för den första parametern. I stället skickar systemet automatiskt det obligatoriska objektet för den första parametern.
  • Målet för en tilläggsmetod måste vara en klass, tabell, vy eller mappning av programobjekttyp.

En tilläggsklass kan innehålla privata eller skyddade statiska metoder. Dessa metoder används vanligtvis för implementeringsinformation och exponeras inte som tillägg. Tilläggsmetodtekniken påverkar inte källkoden för den klass som den utökar, därför kräver tillägget till klassen inte överskiktning.

Uppgraderingar till målklassen påverkas aldrig av några befintliga tilläggsmetoder. Om en uppgradering till målklassen lägger till en metod som har samma namn som tilläggsmetoden kan tilläggsmetoden inte längre nås via objekt i målklassen. Metoden extension använder samma punktavgränsade syntax som du ofta använder för att anropa vanliga instansmetoder. Tilläggsmetoder kan komma åt alla offentliga artefakter i målklassen, men de kan inte komma åt något som är skyddat eller privat. Därför kan förlängningsmetoder betraktas som en typ av syntaktiskt socker. Oavsett måltyp används en tilläggsklass för att lägga till tilläggsmetoder i typen. En tilläggstabell används till exempel inte för att lägga till metoder i en tabell och det finns inget sådant som en tilläggstabell.

// An example of an extension class holding a few extension methods.
public static class AtlInventLocation_Extension
{
    public static InventLocation refillEnabled(
        InventLocation _warehouse,
        boolean _isRefillEnabled = true)
    {
        _warehouse.ReqRefill = _isRefillEnabled;
        return _warehouse;
    }

    public static InventLocation save(InventLocation _warehouse)
    {
        _warehouse.write();
        return _warehouse;
    }
}

Ombud som datatyper

Ett ombud samlar in metoder som prenumererar på den. Ombudet anger parametersignaturen som alla dess prenumerantmetoder måste dela. När ombudet anropas anropar ombudet var och en av sina prenumeranter. Ett ombud returnerar aldrig ett värde och kan inte ha något standardvärde. Till en början har varje ombud inga prenumerationsmetoder. Det finns ingen gräns för antalet parametrar som ett ombud kan deklarera, och det finns ingen begränsning för typen av dessa parametrar. Ombudstexten är alltid tom eftersom ombudets enda syfte är att definiera det kontrakt som prenumeranterna måste följa. Ett ombud behöver inte definieras i en klass. Ombud kan också definieras i en tabell, ett formulär eller en fråga.

Delegera exempel

abstract class VarDatClass
{

    void new(utcdatetime _dateTime, str _changeDescription)
    {
        // An example of subscribing a delegate.
        this.notifyChanged += eventhandler(this.InfologChanges);
        this.notifyChanged += eventhandler(this.SaveInDatabase);
        
        notifyChange(_dateTime, _changeDescription);
    }

    void notifyChange(utcdatetime _dateTime, str _changeDescription)
    {
        // An example of calling a delegate.
        this.notifyChanged(_dateTime, _changeDescription);
    }
    
    // delegate method examples
    // An example of declaring a delegate.
    delegate void notifyChanged(utcdatetime _dateTime, str _changeDescription)
    {
    }

    // method that is to be subscribed.
    public static void InfologChanges(utcDateTime _dateTime, str _changeDescription)
    {
        info("A notification has occurred calling static handler:" +
            DateTimeUtil::toStr(_dateTime) +
            " Message:" +
            _changeDescription);
    }
    
    // method that is to be subscribed.
    public static void SaveInDatabase(utcDateTime _dateTime, str _changeDescription)
    {
       // save changes in database.
    }
    
    
}

Tabeller som datatyper

Alla tabeller kan behandlas som klassdefinitioner. En tabellvariabel kan betraktas som en instans (objekt) av tabelldefinitionen (klass). För varje fält i en tabellvariabel är standardvärdet tomt. Du kan adressera fält och skapa metoder i tabeller. Metoderna kan anropas på instanser av tabellen. Om du vill ändra (dvs. läsa, uppdatera, infoga och ta bort) poster i tabeller måste du deklarera minst en tabellvariabel som kan hålla posten i fokus. Vi rekommenderar att du använder tabellens namn som namn på variabeln men använder en inledande gemen bokstav. Här följer några viktiga skillnader mellan tabeller och objekt:

  • Du kan inte allokera utrymme för tabellvariabler. Allokeringen görs implicit.
  • Fält i tabellvariabler är offentliga. Du kan referera till dem var som helst.
  • Fält i tabellvariabler kan refereras med hjälp av uttryck.

Det finns ingen automatisk konvertering, men tabellvariabler som deklareras som Gemensamma kan innehålla data från valfri tabell.

Omfång för tabellvariabler

I de flesta avseenden kan tabellvariabler betraktas som objekt, men till skillnad från objekt allokeras de inte uttryckligen. Endast en variabeldeklaration krävs. Alla tabeller är kompatibla med Common-tabellen , precis som alla objekt är kompatibla med klassen Object . Tabellvariabler deklareras som vanliga buffertar och kan användas för att lagra data från valfri tabell. Du kan inte komma åt tabeller som inte har tabellvariabler. Principerna för att deklarera tabellvariabler och objekt är desamma, förutom när det gäller allokering av utrymme.

Tabellexempel

Syntaxen ger olika möjligheter att referera till fält i poster. Du kan till exempel använda TableName.( FieldId) -syntax.

I följande exempel skrivs innehållet i fälten ut i den aktuella posten i tabellen Kund.

// Declares and allocates space for one CustTable record.
public void myMethod()
{
    CustomerTable custTable;
}

// An example of referencing table variables.
public void printAccountNo()
{
    CustomerTable custTable;
    print custTable.AccountNo;  // Prints the field reference.
}

I följande exempel används metoderna fieldCnt och fieldCnt2Id . Metoden fieldCnt räknar antalet fält i en tabell, medan fieldCnt2Id returnerar ID:t för ett fältnummer. Du kan till exempel använda metoden fieldCnt2Id för att lära dig att fältnummer 6 i en tabell har ID 54. Den här konverteringen krävs eftersom det inte finns någon garanti för att fältens ID:n i en tabell är i följd.

// An example of the various possibilities for referencing fields in records.
public void printCust()
{
    int i, n, k;
    CustomerTable custTable;
    DictTable dictTable;
    dictTable = new DictTable(custTable.TableId);
    n = dictTable.fieldCnt();
    print "Number of fields in table: ", n;
    for(i=1; i<=n; i++)
    {
        k = dictTable.fieldCnt2Id(i);
        print "The ", dictTable.fieldName(k),
        " field with Id=",k, " contains '",
        custTable.(k), "'";
    }
}