ชนิดข้อมูลแบบรวม X++

หมายเหตุ

กลุ่มความสนใจของชุมชนได้ย้ายจาก Yammer ไปยัง Microsoft Viva Engage แล้ว หากต้องการเข้าร่วมชุมชน Viva Engage และเข้าร่วมในการสนทนาล่าสุด ให้กรอก แบบฟอร์ม คําขอการเข้าถึงการเงินและการดําเนินงาน Viva Engage Community และเลือกชุมชนที่คุณต้องการเข้าร่วม

บทความนี้อธิบายชนิดข้อมูลแบบรวมใน X++ ชนิดข้อมูลแบบรวมใน X++ คืออาร์เรย์ คอนเทนเนอร์ คลาสเป็นชนิดข้อมูล มอบหมายเป็นชนิดข้อมูล และตารางเป็นชนิดข้อมูล

อาร์เรย์

อาร์เรย์ เป็นตัวแปรที่ประกอบด้วยรายการของหน่วยข้อมูลที่มีข้อมูลชนิดเดียวกัน มีการเข้าถึงองค์ประกอบของอาร์เรย์โดยใช้ดัชนีจํานวนเต็ม คุณใช้คําสั่งแยกต่างหากเพื่อเริ่มต้นแต่ละองค์ประกอบในอาร์เรย์ เมื่อคุณใช้ชนิดข้อมูลคอนเทนเนอร์หรือออบเจ็กต์อาร์เรย์เพื่อสร้างคอลเลกชัน คุณสามารถเริ่มต้นหลายองค์ประกอบโดยใช้คําสั่งเดียวได้ ตามค่าเริ่มต้น หน่วยข้อมูลทั้งหมดในอาร์เรย์จะมีค่าเริ่มต้นของชนิดข้อมูลในอาร์เรย์ อาร์เรย์มีสามประเภท: อาร์เรย์แบบไดนามิกอาร์เรย์แบบความยาวคงที่ และบางส่วนในอาร์เรย์ของดิสก์

  • อาร์เรย์แบบไดนามิก – อาร์เรย์เหล่านี้จะถูกประกาศโดยใช้ตัวเลือกอาร์เรย์ที่ว่างเปล่า กล่าวอีกนัยหนึ่งคือ มีเพียงเครื่องหมายวงเล็บ ([]) เท่านั้น
  • อาร์เรย์ที่มีความยาวคงที่ – อาร์เรย์เหล่านี้สามารถเก็บจํานวนของรายการที่ระบุไว้ในการประกาศได้ มีการประกาศอาร์เรย์ที่มีความยาวคงที่เหมือนกับอาร์เรย์แบบไดนามิก แต่ตัวเลือกความยาวจะรวมอยู่ในเครื่องหมายวงเล็บ
  • ส่วนหนึ่งของอาร์เรย์ของดิสก์ – อาร์เรย์เหล่านี้จะถูกประกาศเป็นอาร์เรย์แบบไดนามิกหรืออาร์เรย์ที่มีความยาวคงที่ซึ่งมีตัวเลือกเพิ่มเติมที่ประกาศจํานวนรายการที่จะเก็บไว้ในหน่วยความจํา รายการอื่นๆ จะถูกเก็บไว้บนดิสก์และโหลดโดยอัตโนมัติเมื่อมีการอ้างอิง

X++ สนับสนุนอาร์เรย์แบบมิติเดียวเท่านั้น อย่างไรก็ตาม คุณสามารถเลียนแบบลักษณะการทํางานของดัชนีอาร์เรย์หลายรายการได้ (สําหรับข้อมูลเพิ่มเติม ให้ดูส่วน ดัชนีอาร์เรย์หลาย รายการ) สามารถประกาศตัวแปรในออบเจ็กต์และตารางเป็นอาร์เรย์ได้ ฟังก์ชันนี้จะใช้ในบรรทัดที่อยู่ในแอพลิเคชันมาตรฐาน คลาสคอลเลกชันอาร์เรย์ช่วยให้คุณจัดเก็บออบเจ็กต์ในอาร์เรย์

ดัชนีอาร์เรย์เริ่มต้นที่ 1 หน่วยข้อมูลแรกในอาร์เรย์ จะถูกอ้างอิงเป็น [1] หน่วยข้อมูลที่สองถูกอ้างอิงเป็น [2] และอื่น ๆ ไวยากรณ์ต่อไปนี้ถูกใช้เพื่อเข้าถึงองค์ประกอบอาร์เรย์: ArrayItemReference = ArrayVariable [ Index ] ในไวยากรณ์นี้ ArrayVariable เป็นตัวระบุของอาร์เรย์ และ ดัชนี คือหมายเลขขององค์ประกอบอาร์เรย์ ดัชนี สามารถเป็นนิพจน์จํานวนเต็ม Item zero [0] จะถูกใช้เพื่อล้างอาร์เรย์ ถ้ามีการกําหนดค่า ให้กับดัชนี 0 ในอาร์เรย์ องค์ประกอบทั้งหมดในอาร์เรย์จะถูกรีเซ็ตเป็นค่าเริ่มต้น

มีการดําเนินการการกําหนดอาร์เรย์ทั้งหมดหนึ่งอาร์เรย์ไปยังอีกอาร์เรย์หนึ่งโดยการอ้างอิง

ตัวอย่างอาร์เรย์

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

ดัชนีอาร์เรย์หลายรายการ

บางภาษา เช่น C++ และ C# ช่วยให้คุณสามารถประกาศอาร์เรย์ที่มีมากกว่าหนึ่งดัชนีได้ กล่าวอีกนัยหนึ่งคุณสามารถกําหนด "อาร์เรย์ของอาร์เรย์" ใน X++ คุณไม่สามารถสร้างดัชนีอาร์เรย์หลายรายการได้โดยตรง เนื่องจากมีการสนับสนุนอาร์เรย์ขนาดเดียวเท่านั้น อย่างไรก็ตาม คุณสามารถใช้ดัชนีหลายรายการได้โดยใช้วิธีการที่อธิบายไว้ในส่วนนี้ ตัวอย่างเช่น คุณต้องการประกาศอาร์เรย์ที่มีสองมิติ เพื่อเก็บยอดเงินที่ประเทศ/ภูมิภาคได้รับตามมิติ มี 10 ประเทศ/ภูมิภาคและสามมิติ ใน C++ และ C# คุณต้องประกาศอาร์เรย์ต่อไปนี้

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

อย่างไรก็ตาม X++ ไม่รองรับการประกาศนี้ แต่คุณสามารถกําหนดอาร์เรย์แบบมิติเดียวซึ่งจํานวนขององค์ประกอบคือผลขององค์ประกอบในแต่ละมิติได้ นี่คือตัวอย่าง

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

Container

วัตถุ คอนเทนเนอร์ เป็นรายการแบบไดนามิกของรายการที่มีชนิดข้อมูลดั้งเดิมหรือชนิดข้อมูลแบบรวม คอนเทนเนอร์มีประโยชน์เมื่อคุณต้องส่งผ่านค่าชนิดต่าง ๆ ระหว่างระดับไคลเอ็นต์และเซิร์ฟเวอร์ อย่างไรก็ตาม ถ้าคุณวางแผนที่จะเพิ่มลงในรายการซ้ํา ๆ ในการวนรอบ คอนเทนเนอร์ไม่ใช่ตัวเลือกที่ดี ภาชนะบรรจุเหมาะที่สุดสําหรับกระบวนการที่ไม่เกี่ยวข้องกับการปรับเปลี่ยนขนาดหรือเนื้อหาของภาชนะมากเกินไป เมื่อคอนเทนเนอร์มีการเพิ่มข้อมูลมากเกินไป ประสิทธิภาพของระบบโดยรวมอาจลดลงได้ เนื่องจากต้องคัดลอกข้อมูลคอนเทนเนอร์ซ้ํา ๆ และต้องจัดสรรพื้นที่ใหม่ซ้ํา ๆ

คอนเทนเนอร์ไม่ใช่คลาส คอนเทนเนอร์ประกอบด้วยลําดับค่าดั้งเดิมหรือคอนเทนเนอร์อื่น ๆ ที่มีการเรียงลําดับ เนื่องจากความยืดหยุ่นของ ชนิดใดก็ตาม คอนเทนเนอร์จึงเป็นวิธีที่ดีในการจัดเก็บค่าของประเภทต่าง ๆ เข้าด้วยกัน คอนเทนเนอร์สามารถจัดเก็บไว้ในฐานข้อมูลได้ คอนเทนเนอร์เป็นหนึ่งในชนิดคอลัมน์ที่คุณสามารถเลือกได้เมื่อคุณใช้ Application Explorer เพื่อเพิ่มคอลัมน์ลงในตาราง คอนเทนเนอร์คล้ายกับอาร์เรย์หรือคอลเลกชันเล็กน้อย เช่น รายการ หรือคลาสสแตก อย่างไรก็ตาม คุณไม่สามารถเปลี่ยนขนาดหรือเนื้อหาของคอนเทนเนอร์หลังจากที่สร้างคอนเทนเนอร์แล้ว

คําสั่ง X++ ที่ปรากฏขึ้นเพื่อปรับเปลี่ยนคอนเทนเนอร์คือการสร้างคอนเทนเนอร์ใหม่ภายในและคัดลอกค่าตามที่จําเป็น แม้แต่การกําหนดคอนเทนเนอร์ให้กับตัวแปรคอนเทนเนอร์อื่นจะสร้างสําเนาใหม่ของคอนเทนเนอร์ การดําเนินการเหล่านี้ทั้งหมดอาจส่งผลกระทบต่อประสิทธิภาพการทํางาน ในฟังก์ชันที่ให้การเข้าถึงคอนเทนเนอร์ (เช่น conPeek) คอนเทนเนอร์เป็นแบบ 1 ไม่ใช่แบบ 0 การทําดัชนีจะขึ้นอยู่กับ 1 สําหรับอาร์เรย์ ค่าเริ่มต้นของคอนเทนเนอร์จะว่างเปล่า คอนเทนเนอร์ไม่มีค่าใดๆ คําสั่งบางอย่างที่ใช้คอนเทนเนอร์อาจปรากฏขึ้นเพื่อปรับเปลี่ยนคอนเทนเนอร์ อย่างไรก็ตามภายในระบบ คอนเทนเนอร์จะไม่ถูกปรับเปลี่ยน แต่จะมีการรวมข้อมูลจากคอนเทนเนอร์เดิมเข้ากับข้อมูลจากคําสั่งเพื่อสร้างคอนเทนเนอร์ใหม่ คุณสามารถสร้างคอนเทนเนอร์ใหม่โดยใช้หนึ่งในฟังก์ชันต่อไปนี้: conDel, conIns หรือ conPoke

นอกจากนี้ คลาส ส่วนกลาง มีวิธีการแบบคงที่สําหรับการจัดการคอนเทนเนอร์ วิธีการเหล่านี้รวมถึง con2ArraySource, con2Buf, con2List, con2Str, containerFromXmlNode, conView และ str2Con มีฟังก์ชันอินทรินซิกมากมายสําหรับการจัดการคอนเทนเนอร์ เช่น conIns และ conPeek ฟังก์ชัน X++ conPeek จะส่งกลับชนิด ใดก็ตาม ดังนั้นจึงง่ายต่อการอ่านค่าจากคอนเทนเนอร์เมื่อคุณไม่ทราบชนิดของค่าแต่ละค่า สามารถกําหนด ชนิด anytype ให้กับชนิดค่า X++ ใด ๆ โดยที่ค่าสามารถแปลงได้ คุณสามารถอ่านโค้ดของคุณได้ง่ายขึ้นเมื่อหลีกเลี่ยงการแปลงชนิดข้อมูลที่ชัดเจน ดังนั้น ให้กําหนดค่าจากคอนเทนเนอร์ให้กับข้อมูลชนิดเดียวกันที่ใช้เพื่อใส่ค่าลงในคอนเทนเนอร์ คุณต้องไม่กําหนดคอนเทนเนอร์ให้กับ ชนิดใดก็ตาม เนื่องจากระบบอาจไม่สามารถกําหนดการแปลงที่ถูกต้องได้ ในกรณีเหล่านี้ อาจเกิดลักษณะการทํางานที่ไม่คาดคิดหรือข้อผิดพลาด

การเปรียบเทียบคอนเทนเนอร์กับตัวเลือกอื่นๆ

ชนิดคอนเทนเนอร์คล้ายกับโครงสร้างอื่น ๆ เช่น อาร์เรย์ และคลาสคอลเลกชัน เช่น รายการและสแตก ความแตกต่างระหว่าง คอนเทนเนอร์ และ รายการ คืออินสแตนซ์ของคลาส รายการ นั้นเสถียร ก่อนอื่นวัตถุ รายการ ได้จัดสรรช่องว่างมากกว่าที่ข้อมูลใช้ จากนั้น เมื่อมีการเพิ่มข้อมูล ช่องว่างจะถูกเติม ลักษณะการทํางานนี้จะมีประสิทธิภาพมากกว่าการจัดสรรพื้นที่เพิ่มเติมทุกครั้งที่มีการเพิ่มองค์ประกอบ การอัปเดต รายการ ทํางานได้เร็วกว่าการดําเนินการที่คล้ายกันบนคอนเทนเนอร์

เมื่อคุณสร้างวัตถุ รายการ คุณจะกําหนดชนิดข้อมูลหนึ่งที่วัตถุ รายการ สามารถจัดเก็บได้ ข้อจํากัดนี้มีความยืดหยุ่นสําหรับ รายการ น้อยกว่าสําหรับคอนเทนเนอร์ อย่างไรก็ตาม คุณสามารถจัดเก็บออบเจ็กต์ในรายการในขณะที่คอนเทนเนอร์สามารถจัดเก็บได้เฉพาะชนิดค่าเท่านั้น ความแตกต่างระหว่างคอนเทนเนอร์และอาร์เรย์คืออาร์เรย์สามารถเก็บได้เฉพาะรายการของประเภทที่ประกาศเท่านั้น คุณสามารถจัดสรรพื้นที่หน่วยความจําสําหรับอาร์เรย์ และเติมช่องว่างนั้นด้วยค่าในภายหลังได้ ตัวอย่างเช่น คุณสามารถกรอกข้อมูลในค่าแบบวนรอบได้ ลักษณะการทํางานนี้มีประสิทธิภาพและทํางานได้ดี เมื่อคุณต้องการสร้างคอนเทนเนอร์ใหม่โดยการผนวกข้อมูลใหม่ คุณสามารถใช้ตัว += ดําเนินการหรือฟังก์ชัน conIns ได้ ตัว += ดําเนินการ เป็นทางเลือกที่เร็วกว่า ใช้ฟังก์ชัน conIns เฉพาะเมื่อคุณต้องการเพิ่มข้อมูลใหม่ก่อนดัชนีล่าสุดของข้อมูลต้นฉบับ

คุณไม่สามารถจัดเก็บการอ้างอิงวัตถุในคอนเทนเนอร์ เมื่อคอมไพเลอร์ตรวจพบความพยายามที่จะเก็บการอ้างอิงวัตถุในคอนเทนเนอร์ จะออกข้อความแสดงข้อผิดพลาด หากชนิดขององค์ประกอบที่เพิ่มลงในคอนเทนเนอร์เป็น ชนิดใดก็ตาม คอมไพเลอร์จะไม่สามารถกําหนดได้ว่าค่าเป็นประเภทการอ้างอิงหรือไม่ ในกรณีนี้ คอมไพเลอร์ช่วยให้พยายาม แม้ว่าคอมไพเลอร์ไม่ได้วินิจฉัยรหัสว่ามีข้อผิดพลาด แต่ข้อผิดพลาดจะถูกโยนในขณะทํางาน

ตัวอย่างคอนเทนเนอร์

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

คลาสเป็นชนิดข้อมูล

คลาส คือข้อกําหนดชนิดที่อธิบายทั้งตัวแปรและวิธีการสําหรับอินสแตนซ์ของคลาส (อินสแตนซ์ของคลาสจะเรียกอีกอย่างว่า ออบเจ็กต์) คลาส เป็นข้อกําหนดสําหรับออบเจ็กต์เท่านั้น และออบเจ็กต์ทั้งหมดเป็น null เมื่อมีการประกาศ ใน Application Explorer ทุกคลาสแอปพลิเคชันภายใต้โหนด คลาส เป็นชนิดข้อมูล คุณสามารถประกาศตัวแปรของชนิดเหล่านี้ในโค้ดของคุณ คุณสามารถสร้างอินสแตนซ์ของคลาสและกําหนดอินสแตนซ์ให้กับตัวแปรได้

คลาสสามารถซ้อนกันในโค้ดต้นฉบับได้ คลาสแบบซ้อนกันจะพร้อมใช้งานเฉพาะภายในฟอร์มเท่านั้น (เช่น คลาสที่ขยาย FormRun) และใช้เพื่อแสดงตัวควบคุม แหล่งข้อมูล หรือเขตข้อมูล การตกแต่งแอตทริบิวต์ เช่น การตกแต่งแอตทริบิวต์บนคลาสหรือเมธอด สามารถละเว้นคําต่อท้ายของชื่อแอตทริบิวต์ถ้าคําต่อท้ายเป็นแอตทริบิวต์ ดังนั้น X++ อนุญาต [MyFavorite] แทนที่จะต้องใช้ [MyFavoriteAttribute] นอกจากนี้ แอตทริบิวต์จะถูกนําไปใช้กับตัวจัดการของผู้รับมอบสิทธิ์และวิธีการ เพื่อแมปตัวจัดการไปยังเป้าหมายเหล่านั้น

ใน AX 2012 และเวอร์ชันก่อนหน้า คุณสามารถกําหนดวิธีการที่จะรันบนไคลเอนต์หรือเซิร์ฟเวอร์ได้ อย่างไรก็ตาม ในแอปพลิเคชันการเงินและการดําเนินงาน โค้ด X++ ที่คอมไพล์ทั้งหมดจะถูกเรียกใช้เป็น .NET Common Intermediate Language (CIL) บนเซิร์ฟเวอร์ ไม่มีโค้ดใด ๆ ที่มีการประเมินที่ไซต์ไคลเอ็นต์หรือในเบราว์เซอร์อีกต่อไป ดังนั้น คําหลัก ไคลเอ็นต์ และ เซิร์ฟเวอร์ จะถูกละเว้น แม้ว่าคําหลักเหล่านี้จะไม่ทําให้เกิดข้อผิดพลาดในการคอมไพล์หากใช้คําเหล่านี้ แต่ไม่ควรใช้ในรหัสใหม่ใด ๆ

ตัวแปรสมาชิกส่วนตัวและป้องกัน

ก่อนหน้านี้ ตัวแปรสมาชิกทั้งหมดที่กําหนดไว้ในคลาสได้รับการป้องกัน ตอนนี้คุณสามารถมองเห็นตัวแปรสมาชิกได้อย่างชัดเจนโดยการเพิ่มคําหลักส่วนตัวการป้องกันและสาธารณะ การตีความของตัวแก้ไขเหล่านี้ชัดเจนและสอดคล้องกับความหมายสําหรับวิธีการ:

  • private – ตัวแปรสมาชิกสามารถใช้ได้เฉพาะภายในคลาสที่กําหนดเท่านั้น
  • protected – ตัวแปรสมาชิกสามารถใช้ในคลาสที่กําหนดไว้และคลาสย่อยทั้งหมดของคลาสนั้น
  • public – ตัวแปรสมาชิกสามารถใช้ได้ทุกที่ สามารถมองเห็นได้นอกขอบเขตของลําดับชั้นของคลาสที่กําหนดไว้

ตามค่าเริ่มต้น ตัวแปรสมาชิกที่ไม่ได้ประดับด้วยตัวแก้ไขอย่างชัดเจนจะยังคงได้รับการป้องกัน อย่างไรก็ตาม แนวทางปฏิบัติที่ดีที่สุด คุณควรระบุการมองเห็นอย่างชัดเจน ดังที่เราได้อธิบายไว้ก่อนหน้านี้ เมื่อมีการกําหนดตัวแปรสมาชิกเป็น สาธารณะ ตัวแปรดังกล่าวจะสามารถเข้าถึงภายนอกคลาสที่กําหนดไว้ ในกรณีนี้ คุณต้องระบุตัวบ่งคุณลักษณะที่กําหนดวัตถุที่โฮสต์ตัวแปร เมื่อต้องการระบุตัวบ่งคุณลักษณะ ให้ใช้เครื่องหมายจุด เช่นเดียวกับที่คุณทําสําหรับการเรียกเมธอด

ในตัวอย่างต่อไปนี้ field1 เข้าถึงได้โดยใช้ตัวบ่งคุณลักษณะ นี้ อย่างชัดเจน ในกรณีนี้อาจไม่ใช่ความคิดที่ดีที่จะทําให้ตัวแปรสมาชิกเป็นสาธารณะเนื่องจากวิธีการดังกล่าวแสดงถึงการทํางานภายในของคลาสกับผู้บริโภคดังนั้นจึงสร้างการขึ้นต่อกันที่แข็งแกร่งระหว่างการใช้งานคลาสและผู้บริโภค คุณควรพยายามขึ้นอยู่กับสัญญาเท่านั้นไม่ใช่การใช้งาน

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

คอนสตรัคเตอร์แบบคงที่และเขตข้อมูลแบบคงที่

เขตข้อมูลแบบคงที่คือเขตข้อมูลที่ถูกประกาศโดยใช้คําสําคัญแบบคงที่ ตามแนวคิดแล้ว เขตข้อมูลแบบคงที่ใช้กับคลาส ไม่ใช่กับอินสแตนซ์ของคลาส คอนสตรัคเตอร์แบบคงที่จะรับประกันว่าจะเรียกใช้ก่อนที่จะเรียกใช้แบบคงที่หรือการเรียกอินสแตนซ์ใด ๆ กับคลาส การดําเนินการของคอนสตรักเตอร์แบบคงที่จะเกี่ยวข้องกับเซสชันของผู้ใช้ คุณไม่เคยเรียกใช้คอนสตรักเตอร์แบบคงที่อย่างชัดเจน แต่คอมไพเลอร์จะสร้างโค้ดเพื่อให้แน่ใจว่าคอนสตรักเตอร์ถูกเรียกเพียงครั้งเดียวก่อนที่จะมีการเรียกวิธีการอื่นในคลาส คอนสตรักเตอร์แบบคงที่ถูกใช้เพื่อเริ่มต้นข้อมูลแบบคงที่ใด ๆ หรือดําเนินการที่ต้องดําเนินการเพียงครั้งเดียว คุณไม่สามารถใส่พารามิเตอร์สําหรับคอนสตรักเตอร์แบบคงที่ได้ และต้องทําเครื่องหมายด้วยคําสําคัญแบบคงที่

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

องค์ประกอบคลาสใน Application Explorer

ภายใต้โหนดคลาสส่วนใหญ่ใน Application Explorer มีโหนดพิเศษสองโหนด: โหนดคลาสการประกาศและโหนดใหม่ classDeclaration จะประกอบด้วยคําสําคัญคลาส X++ เสมอ คําสําคัญเพิ่มเติม เช่น การขยาย สามารถถูกรวมไว้เพื่อปรับเปลี่ยนคลาส โหนดนี้ยังสามารถมีการประกาศตัวแปรสมาชิกอีกด้วย

ในตัวอย่างต่อไปนี้ ตัวแปร m_priority และ m_rectangle เป็นสมาชิกของคลาส

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

ตัวดําเนินการ ใหม่ มีตรรกะที่จะเรียกใช้เมื่อตัวดําเนินการ ใหม่ ถูกใช้เพื่อสร้างอินสแตนซ์ของคลาส ตรรกะในเมธอดใหม่อาจสร้างออบเจ็กต์และกําหนดออบเจ็กต์นั้นให้กับตัวแปรที่ถูกประกาศใน classDeclaration แต่ละคลาสสามารถมีวิธี ใหม่ ได้เพียงวิธีเดียวเท่านั้น อย่างไรก็ตาม ในวิธีการ ใหม่ คุณมักจะเรียกเมธอด ใหม่ ของคลาสฐาน เมื่อต้องการเรียกใช้เมธอดใหม่ของคลาสพื้นฐาน ให้เรียกใช้ super()

ตัวอย่างต่อไปนี้แสดงวิธีการใหม่สําหรับคลาส YourDerivedClass ในตัวอย่างคลาสก่อนหน้าประกาศ ในวิธีการใหม่นี้ โค้ดจะสร้างอินสแตนซ์ของคลาสสี่เหลี่ยมผืนผ้า อินสแตนซ์จะถูกกําหนดให้กับตัวแปร m_rectangle คําหลักนี้ที่ใช้ในตัวอย่างเป็นตัวเลือก อย่างไรก็ตาม ถ้าคุณใส่คํา สําคัญนี้ IntelliSense อาจมีประโยชน์มากขึ้น

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

การเก็บขยะ

ในที่สุดในระหว่างเวลาทํางาน ออบเจ็กต์ส่วนใหญ่จะไม่มีตัวแปรใด ๆ ที่ชี้ไปยังตัวแปรเหล่านั้นอีกต่อไป ระบบจะสแกนหาวัตถุเหล่านี้และลบออกจากหน่วยความจํา เนื้อที่หน่วยความจําจะพร้อมใช้งานสําหรับการใช้งานอื่น ๆ คลาสออบเจ็กต์ มีเมธอดที่ตั้งชื่อเป็นขั้นสุดท้าย อย่างไรก็ตามวิธีการ สุดท้าย ไม่ใช่ดีสตเตอร์ รันไทม์ไม่เคยเรียกใช้เมธอด สุดท้าย แม้ว่าวัตถุจะถูกเก็บรวบรวมเป็นถังขยะ

คลาสของระบบ

ใน Application Explorer ภายใต้คลาส>ของระบบ จะมีรายการคลาสเคอร์เนลหรือคลาสระบบ ระดับชั้นระบบจะไม่ถูกเขียนใน X++ และคุณไม่สามารถดูโค้ดต้นฉบับได้ คุณไม่สามารถเพิ่มคลาสของระบบได้ คลาสของระบบมักจะมีวิธีการใหม่ แต่ไม่มีโหนดคลาสการประกาศ ทุกคลาสแอปพลิเคชันจะขยายคลาสระบบ ออบเจ็กต์ โดยนัย คลาสของระบบบางอย่างจะถูกขยายโดยคลาสแอปพลิเคชันที่มีชื่อคล้ายกัน ตัวอย่างเช่น xClassFactory จะขยายโดย ClassFactory ในกรณีเหล่านี้ คุณไม่ควรใช้คลาสระบบ สําหรับข้อมูลเพิ่มเติม โปรดดูที่ "คลาสแอพลิเคชันการทดแทนสําหรับคลาสระบบ" ในคลาสและวิธีการ

วิธีการขยาย

คุณลักษณะเมธอดส่วนขยายช่วยให้คุณสามารถเพิ่มวิธีการขยายไปยังคลาสเป้าหมายโดยการเขียนวิธีการในคลาสส่วนขยายที่แยกต่างหาก กฎต่อไปนี้จะมีผลบังคับ

  • คลาสส่วนขยายต้องเป็นแบบคงที่
  • ชื่อของคลาสส่วนขยายต้องลงท้ายด้วยคําต่อท้ายสิบอักขระ _Extension อย่างไรก็ตาม ไม่มีข้อจํากัดในส่วนของชื่อที่อยู่ก่อนหน้าคําต่อท้าย
  • ต้องประกาศเมธอดส่วนขยายทั้งหมดในคลาสส่วนขยายเป็นค่าคงที่สาธารณะ
  • พารามิเตอร์แรกในเมธอดส่วนขยายทุกเมธอดคือชนิดที่เมธอดส่วนขยายขยาย อย่างไรก็ตาม เมื่อมีการเรียกใช้เมธอดส่วนขยาย ผู้เรียกต้องไม่ส่งผ่านในสิ่งใดสําหรับพารามิเตอร์แรก แต่ระบบจะส่งผ่านในวัตถุที่จําเป็นสําหรับพารามิเตอร์แรกโดยอัตโนมัติ
  • เป้าหมายของวิธีการขยายต้องเป็นคลาส ตาราง มุมมอง หรือการแม็ปชนิดออบเจ็กต์แอพลิเคชัน

คลาสส่วนขยายสามารถมีวิธีการแบบคงที่ส่วนตัวหรือป้องกันได้ โดยทั่วไปวิธีการเหล่านี้จะใช้สําหรับรายละเอียดการนําไปใช้งานและจะไม่แสดงเป็นส่วนขยาย เทคนิคเมธอดส่วนขยายไม่มีผลต่อซอร์สโค้ดของคลาสที่ขยาย ดังนั้นการเพิ่มคลาสไม่จําเป็นต้องมีการจัดชั้นมากเกินไป

การอัปเกรดไปยังคลาสเป้าหมายจะไม่ได้รับผลกระทบจากวิธีการขยายใด ๆ ที่มีอยู่ ถ้าการอัปเกรดไปยังคลาสเป้าหมายเพิ่มวิธีการที่มีชื่อเดียวกันกับเมธอดส่วนขยายของคุณ วิธีการส่วนขยายของคุณจะไม่สามารถเข้าถึงได้ผ่านทางออบเจ็กต์ของคลาสเป้าหมายอีกต่อไป เทคนิคเมธอดส่วนขยายใช้ไวยากรณ์แบบมีตัวคั่นจุดเดียวกับที่คุณมักจะใช้เพื่อเรียกใช้เมธอดอินสแตนซ์ปกติ วิธีส่วนขยายสามารถเข้าถึงวัตถุสาธารณะทั้งหมดของคลาสเป้าหมาย แต่ไม่สามารถเข้าถึงสิ่งใด ๆ ที่ได้รับการป้องกันหรือส่วนตัวได้ ดังนั้นวิธีการขยายถือได้ว่าเป็นประเภทของน้ําตาลในเชิงไวยากรณ์ คลาสส่วนขยายจะถูกใช้เพื่อเพิ่มวิธีการขยายไปยังชนิด โดยไม่คํานึงถึงชนิดเป้าหมาย ตัวอย่างเช่น ตารางส่วนขยายไม่ได้ถูกใช้เพื่อเพิ่มวิธีการลงในตาราง และไม่มีสิ่งใดเช่นตารางส่วนขยาย

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

มอบสิทธิ์เป็นชนิดข้อมูล

ผู้รับมอบสิทธิ์จะรวบรวมวิธีการที่สมัครใช้งาน ผู้รับมอบสิทธิ์ระบุลายเซ็นพารามิเตอร์ที่วิธีการของผู้สมัครใช้งานทั้งหมดต้องใช้ร่วมกัน เมื่อมีการเรียกผู้รับมอบสิทธิ์ ผู้รับมอบสิทธิ์จะเรียกใช้สมาชิกแต่ละคน ผู้รับมอบสิทธิ์จะไม่ส่งกลับค่า และ ไม่สามารถมีค่าเริ่มต้นได้ ในตอนแรก ผู้รับมอบสิทธิ์ทุกคนไม่มีวิธีการสมัครสมาชิก ไม่มีขีดจํากัดเกี่ยวกับจํานวนพารามิเตอร์ที่ผู้รับมอบสิทธิ์สามารถประกาศได้ และไม่มีข้อจํากัดเกี่ยวกับชนิดของพารามิเตอร์เหล่านั้น เนื้อความของผู้รับมอบสิทธิ์จะว่างเปล่าเสมอ เนื่องจากวัตถุประสงค์เดียวของผู้รับมอบสิทธิ์คือการกําหนดสัญญาที่สมาชิกต้องสอดคล้อง ผู้รับมอบสิทธิ์ไม่จําเป็นต้องกําหนดในคลาส ผู้รับมอบสิทธิ์ยังสามารถกําหนดในตาราง ฟอร์ม หรือคิวรีได้อีกด้วย

ตัวอย่างการมอบหมาย

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

ตารางเป็นชนิดข้อมูล

ตารางทั้งหมดสามารถถือเป็นข้อกําหนดของคลาสได้ ตัวแปรตารางสามารถถือเป็นอินสแตนซ์ (ออบเจ็กต์) ของข้อกําหนดตาราง (คลาส) สําหรับทุกเขตข้อมูลในตัวแปรตาราง ค่าเริ่มต้นจะว่างเปล่า คุณสามารถระบุที่อยู่ของฟิลด์และสร้างวิธีการในตาราง สามารถเรียกใช้วิธีการ บนอินสแตนซ์ของตารางได้ เมื่อต้องการจัดการระเบียนในตาราง (นั่นคือ อ่าน อัปเดต แทรก และลบ) ในตาราง คุณต้องประกาศตัวแปรตารางอย่างน้อยหนึ่งตัวแปรที่สามารถเก็บระเบียนในโฟกัสได้ แนวทางปฏิบัติที่ดีที่สุดคือ คุณควรใช้ชื่อของตารางเป็นชื่อของตัวแปร แต่ใช้ตัวอักษรพิมพ์เล็กเริ่มต้น ต่อไปนี้คือความแตกต่างที่สําคัญบางประการระหว่างตารางและวัตถุ:

  • คุณไม่สามารถจัดสรรช่องว่างสําหรับตัวแปรตารางได้ การปันส่วนจะดําเนินการโดยปริยาย
  • เขตข้อมูลในตัวแปรตารางจะเป็นแบบสาธารณะ คุณสามารถอ้างอิงได้ทุกที่
  • สามารถอ้างอิงเขตข้อมูลในตัวแปรตารางได้โดยใช้นิพจน์

ไม่มีการแปลงโดยอัตโนมัติ แต่ตัวแปรตารางที่ประกาศเป็น ทั่วไป สามารถเก็บข้อมูลจากตารางใด ๆ ได้

ขอบเขตของตัวแปรตาราง

ในแง่มุมใหส่วนใหญ่ ตัวแปรตารางสามารถพิจารณาเป็นออบเจ็กต์ต่างจากวัตถุ ต่างจากวัตถุ ต่างจากที่ได้รับการจัดสรรอย่างชัดเจน จําเป็นต้องมีการประกาศตัวแปรเท่านั้น ตารางทั้งหมดเข้ากันได้กับตารางทั่วไป เช่นเดียวกับวัตถุทั้งหมดเข้ากันได้กับคลาสออบเจ็กต์ ตัวแปรตารางจะถูกประกาศเป็นบัฟเฟอร์ทั่วไปและสามารถใช้เพื่อเก็บข้อมูลจากตารางใด ๆ ได้ คุณไม่สามารถเข้าถึงตารางที่ไม่มีตัวแปรตารางได้ หลักการสําหรับการประกาศตัวแปรตารางและวัตถุเหมือนกัน ยกเว้นในเรื่องเกี่ยวกับการปันส่วนช่องว่าง

ตัวอย่างตาราง

ไวยากรณ์เปิดใช้งานความเป็นไปได้ต่าง ๆ สําหรับการอ้างอิงเขตข้อมูลในเรกคอร์ด ตัวอย่างเช่น คุณสามารถใช้ TableName( ไวยากรณ์ FieldId)

ตัวอย่างต่อไปนี้พิมพ์เนื้อหาของเขตข้อมูลในเรกคอร์ดปัจจุบันในตารางลูกค้า

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

ตัวอย่างต่อไปนี้ใช้วิธีการ fieldCnt และ fieldCnt2Id วิธีการ fieldCnt นับจํานวนเขตข้อมูลในตาราง ในขณะที่ fieldCnt2Id ส่งกลับ ID สําหรับหมายเลขเขตข้อมูล ตัวอย่างเช่น คุณสามารถใช้เมธอด fieldCnt2Id เพื่อเรียนรู้ว่าเขตข้อมูลหมายเลข 6 ในตารางมี ID 54 ได้ การแปลงนี้จําเป็นเนื่องจากไม่รับประกันว่ารหัสของเขตข้อมูลในตารางจะเรียงกัน

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