หมายเหตุ
การเข้าถึงหน้านี้ต้องได้รับการอนุญาต คุณสามารถลอง ลงชื่อเข้าใช้หรือเปลี่ยนไดเรกทอรีได้
การเข้าถึงหน้านี้ต้องได้รับการอนุญาต คุณสามารถลองเปลี่ยนไดเรกทอรีได้
หมายเหตุ
กลุ่มความสนใจของชุมชนได้ย้ายจาก 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), "'";
}
}