नोट
इस पेज तक पहुँच के लिए प्रमाणन की आवश्यकता होती है. आप साइन इन करने या निर्देशिकाओं को बदलने का प्रयास कर सकते हैं.
इस पेज तक पहुँच के लिए प्रमाणन की आवश्यकता होती है. आप निर्देशिकाओं को बदलने का प्रयास कर सकते हैं.
नोट
समुदाय रुचि समूह अब Yammer से Microsoft Viva Engage पर स्थानांतरित हो गए हैं. किसी Viva Engage समुदाय में शामिल होने और नवीनतम चर्चाओं में भाग लेने के लिए,
यह आलेख X++ में समग्र डेटा प्रकारों का वर्णन करता है. X++ में समग्र डेटा प्रकार सरणियाँ, कंटेनर, डेटा प्रकार के रूप में कक्षाएं, डेटा प्रकार के रूप में प्रतिनिधि और डेटा प्रकार के रूप में तालिकाएँ हैं।
सरणी
एक सरणी एक चर है जिसमें उन आइटमों की एक सूची होती है जिनमें समान डेटा प्रकार होता है। एक सरणी के तत्वों को पूर्णांक अनुक्रमणिका का उपयोग करके एक्सेस किया जाता है। आप एक सरणी में प्रत्येक तत्व को प्रारंभ करने के लिए एक अलग कथन का उपयोग करें। जब आप किसी संग्रह को बनाने के लिए किसी कंटेनर डेटा प्रकार या किसी सरणी ऑब्जेक्ट का उपयोग करते हैं, तो आप एक कथन का उपयोग करके एकाधिक तत्वों को प्रारंभ कर सकते हैं। डिफ़ॉल्ट रूप से, किसी सरणी में सभी आइटम्स सरणी में डेटा प्रकार का डिफ़ॉल्ट मान होता है. सरणियाँ तीन प्रकार की होती हैं: गतिशील सरणियाँ, निश्चित-लंबाई सरणियाँ, और आंशिक रूप से डिस्क सरणियों पर।
- गतिशील सरणियाँ - इन सरणियों को एक खाली सरणी विकल्प का उपयोग करके घोषित किया जाता है। दूसरे शब्दों में, उनके पास केवल कोष्ठक ([]) हैं।
- फिक्स्ड-लेंथ एरेज़ - ये सरणियाँ घोषणा में निर्दिष्ट वस्तुओं की संख्या को पकड़ सकती हैं। निश्चित-लंबाई सरणियों को गतिशील सरणियों की तरह घोषित किया जाता है, लेकिन कोष्ठक में एक लंबाई विकल्प शामिल है।
- आंशिक रूप से डिस्क सरणियों पर - इन सरणियों को या तो गतिशील सरणियों या निश्चित-लंबाई सरणियों के रूप में घोषित किया जाता है जिनके पास एक अतिरिक्त विकल्प होता है जो घोषणा करता है कि स्मृति में कितने आइटम रखे जाने चाहिए। अन्य आइटम डिस्क पर संग्रहीत होते हैं और संदर्भित होने पर स्वचालित रूप से लोड हो जाते हैं।
X++ केवल एक-आयामी सरणियों का समर्थन करता है। हालाँकि, आप एकाधिक सरणी अनुक्रमणिका के व्यवहार की नकल कर सकते हैं। (अधिक जानकारी के लिए, एकाधिक सरणी अनुक्रमणिका अनुभाग देखें)। वस्तुओं और तालिकाओं में चर को सरणियों के रूप में घोषित किया जा सकता है। उदाहरण के लिए, इस कार्यक्षमता का उपयोग मानक अनुप्रयोग में पता पंक्तियों में किया जाता है। एक सरणी संग्रह वर्ग आपको ऑब्जेक्ट्स को एक सरणी में संग्रहीत करने देता है।
सरणी अनुक्रमणिका 1 से शुरू होती है। सरणी में पहले आइटम को [1] के रूप में संदर्भित किया गया है, दूसरे आइटम को [2] के रूप में संदर्भित किया गया है, और इसी तरह। किसी सरणी तत्व तक पहुँचने के लिए निम्न सिंटैक्स का उपयोग किया जाता है: ArrayItemReference = ArrayVariable [अनुक्रमणिका]। इस सिंटैक्स में, ArrayVariable सरणी का पहचानकर्ता है, और Index सरणी तत्व की संख्या है। सूचकांक एक पूर्णांक अभिव्यक्ति हो सकती है। आइटम शून्य [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)
}
कंटेनर
एक कंटेनर ऑब्जेक्ट आइटम की एक गतिशील सूची है जिसमें आदिम डेटा प्रकार या समग्र डेटा प्रकार होते हैं। एक कंटेनर तब उपयोगी होता है जब आपको क्लाइंट और सर्वर स्तरों के बीच विभिन्न प्रकार के मानों को पास करना होता है। हालाँकि, यदि आप लूप में किसी सूची में बार-बार जोड़ने की योजना बनाते हैं, तो कंटेनर एक अच्छा विकल्प नहीं है। कंटेनर उन प्रक्रियाओं के लिए सबसे उपयुक्त हैं जिनमें कंटेनर के आकार या सामग्री में अत्यधिक संशोधन शामिल नहीं है। जब कोई कंटेनर डेटा के अत्यधिक परिवर्धन से गुजरता है, तो समग्र सिस्टम प्रदर्शन कम हो सकता है क्योंकि कंटेनर डेटा को बार-बार कॉपी किया जाना चाहिए और नया स्थान बार-बार आवंटित किया जाना चाहिए।
एक कंटेनर एक वर्ग नहीं है। एक कंटेनर में आदिम मूल्यों या अन्य कंटेनरों का एक क्रमबद्ध अनुक्रम होता है। किसी भी प्रकार के लचीलेपन के कारण, एक कंटेनर विभिन्न प्रकार के मूल्यों को एक साथ संग्रहीत करने का एक अच्छा तरीका प्रदान करता है। एक कंटेनर को डेटाबेस में संग्रहीत किया जा सकता है। कंटेनर उन स्तंभ प्रकारों में से एक होता है जिन्हें आप किसी तालिका में स्तंभ जोड़ने के लिए अनुप्रयोग एक्सप्लोरर का उपयोग करते समय चुन सकते हैं. एक कंटेनर थोड़ा एक सरणी, या संग्रह, जैसे सूची या स्टैक वर्गों जैसा दिखता है। हालाँकि, कंटेनर बनने के बाद आप कभी भी कंटेनर का आकार या सामग्री नहीं बदल सकते।
X++ कथन जो एक कंटेनर को संशोधित करने के लिए प्रकट होते हैं, आंतरिक रूप से एक नया कंटेनर बना रहे हैं और आवश्यकतानुसार मानों की प्रतिलिपि बना रहे हैं। यहां तक कि एक कंटेनर का एक असाइनमेंट किसी अन्य कंटेनर चर के लिए कंटेनर की एक नई प्रति बनाता है। ये सभी ऑपरेशन प्रदर्शन को प्रभावित कर सकते हैं। कंटेनर (जैसे conPeek) तक पहुंच प्रदान करने वाले कार्यों में, कंटेनर 1-आधारित है, 0-आधारित नहीं। सरणियों के लिए अनुक्रमण 1-आधारित है। किसी कंटेनर का डिफ़ॉल्ट मान रिक्त है. कंटेनर में कोई मान नहीं है। कंटेनरों का उपयोग करने वाले कुछ कथन एक कंटेनर को संशोधित करने के लिए प्रतीत हो सकते हैं, हालांकि, सिस्टम के अंदर, कंटेनरों को कभी भी संशोधित नहीं किया जाता है। इसके बजाय, मूल कंटेनर के डेटा को एक नया कंटेनर बनाने के लिए कमांड के डेटा के साथ जोड़ा जाता है। आप निम्न फ़ंक्शंस में से किसी एक का उपयोग करके एक नया कंटेनर बना सकते हैं: conDel, conIns, या conPoke.
इसके अतिरिक्त, ग्लोबल क्लास में कंटेनरों को संभालने के लिए स्थिर तरीके हैं। इन विधियों में con2ArraySource, con2Buf, con2List, con2Str, containerFromXmlNode, conView, और str2Con शामिल हैं। कंटेनर को संभालने के लिए कई आंतरिक कार्य हैं, जैसे कि conIns और conPeek। X++ conPeek फ़ंक्शन किसी भी प्रकार का रिटर्न देता है, इसलिए, कंटेनर से मानों को पढ़ना आसान होता है जब आप प्रत्येक मान के प्रकार को नहीं जानते हैं। किसी भी प्रकार को किसी भी X++ मान प्रकार को सौंपा जा सकता है, बशर्ते कि मान को परिवर्तित किया जा सके। जब आपका कोड स्पष्ट डेटा प्रकार रूपांतरणों से बचता है, तो उसे पढ़ना आसान हो जाता है. इसलिए, किसी कंटेनर से मान उसी डेटा प्रकार को असाइन करें जिसका उपयोग मान को कंटेनर में डालने के लिए किया गया था। आपको किसी भी प्रकार के लिए कंटेनर असाइन नहीं करना चाहिए क्योंकि सिस्टम सही रूपांतरणों का निर्धारण करने में सक्षम नहीं हो सकता है। इन मामलों में, अनपेक्षित व्यवहार या त्रुटियाँ हो सकती हैं।
कंटेनर की तुलना अन्य विकल्पों से करना
कंटेनर प्रकार अन्य निर्माणों जैसा दिखता है, जैसे कि सरणियाँ और संग्रह वर्ग, जैसे सूची और स्टैक। एक कंटेनर और सूची के बीच का अंतर यह है कि सूची वर्ग का एक उदाहरण परिवर्तनशील है। एक सूची ऑब्जेक्ट पहले अपने डेटा की खपत की तुलना में अधिक स्थान आवंटित करता है। फिर, जैसे ही डेटा जोड़ा जाता है, स्थान भर जाता है। यह व्यवहार हर बार किसी तत्व को जोड़ने पर अधिक स्थान आवंटित करने से अधिक कुशल है। किसी सूची का अद्यतन किसी कंटेनर पर समान कार्रवाइयों की तुलना में तेज़ प्रदर्शन करता है.
जब आप किसी सूची ऑब्जेक्ट का निर्माण करते हैं, तो आप एक प्रकार का डेटा निर्धारित करते हैं जो सूची ऑब्जेक्ट संग्रहीत कर सकता है। यह प्रतिबंध एक कंटेनर की तुलना में एक सूची के लिए कम लचीला है। हालाँकि, आप ऑब्जेक्ट्स को सूची में संग्रहीत कर सकते हैं, जबकि एक कंटेनर केवल मान प्रकार संग्रहीत कर सकता है। एक कंटेनर और एक सरणी के बीच का अंतर यह है कि एक सरणी केवल अपने घोषित प्रकार की वस्तुओं को पकड़ सकती है। आप किसी सरणी के लिए स्मृति स्थान आवंटित कर सकते हैं और बाद में उस स्थान को मानों से भर सकते हैं। उदाहरण के लिए, आप एक लूप में मान भर सकते हैं। यह व्यवहार कुशल है और अच्छा प्रदर्शन करता है। जब आप नया डेटा जोड़कर एक नया कंटेनर बनाना चाहते हैं, तो आप ऑपरेटर या += फ़ंक्शन का उपयोग कर सकते हैं। += ऑपरेटर सबसे तेज़ विकल्प है। 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];
}
डेटा प्रकारों के रूप में कक्षाएं
एक वर्ग एक प्रकार की परिभाषा है जो वर्ग के उदाहरणों के लिए चर और विधियों दोनों का वर्णन करती है। (किसी वर्ग के उदाहरणों को ऑब्जेक्ट के रूप में भी जाना जाता है। एक वर्ग केवल वस्तुओं के लिए एक परिभाषा है, और सभी वस्तुएं घोषित होने पर शून्य हो जाती हैं। अनुप्रयोग एक्सप्लोरर में, वर्ग नोड के अंतर्गत प्रत्येक अनुप्रयोग वर्ग एक डेटा प्रकार है। आप अपने कोड में इस प्रकार के चर घोषित कर सकते हैं। आप किसी वर्ग के उदाहरण बना सकते हैं और उदाहरणों को चर को असाइन कर सकते हैं।
कक्षाओं को स्रोत कोड में नेस्टेड किया जा सकता है। नेस्टेड कक्षाएं केवल प्रपत्रों के अंदर उपलब्ध होती हैं (जैसे कि एक वर्ग जो FormRun का विस्तार करती है), और नियंत्रण, डेटा स्रोतों या डेटा फ़ील्ड का प्रतिनिधित्व करने के लिए उपयोग की जाती हैं। एक विशेषता सजावट, जैसे कि किसी वर्ग या विधि पर विशेषता सजावट, विशेषता नाम के प्रत्यय को छोड़ सकती है यदि प्रत्यय विशेषता है। इसलिए, X++ [MyFavoriteAttribute] की आवश्यकता के बजाय [MyFavoriteAttribute] की अनुमति देता है। साथ ही, विशेषताएँ अब प्रतिनिधियों और विधियों के हैंडलर के लिए लागू होते हैं, उन लक्ष्यों के लिए हैंडलर मैप करने के लिए।
AX 2012 और पूर्व संस्करणों में, आप क्लाइंट या सर्वर पर चलाने के लिए एक विधि निर्दिष्ट कर सकते हैं। हालाँकि, वित्त और संचालन अनुप्रयोगों में, सभी संकलित X++ कोड सर्वर पर .NET कॉमन इंटरमीडिएट लैंग्वेज (CIL) के रूप में चलाया जाता है। अब कोई भी कोड नहीं है जिसका मूल्यांकन क्लाइंट साइट या ब्राउज़र में किया जाता है। इसलिए, क्लाइंट और सर्वर कीवर्ड अब अनदेखा कर दिए जाते हैं। हालांकि इन कीवर्ड का उपयोग किए जाने पर संकलन त्रुटि का कारण नहीं बनता है, लेकिन इनका उपयोग किसी भी नए कोड में नहीं किया जाना चाहिए.
निजी और संरक्षित सदस्य चर
पहले, किसी वर्ग में परिभाषित किए गए सभी सदस्य चर सुरक्षित थे। अब आप निजी,संरक्षित और सार्वजनिक कीवर्ड जोड़कर सदस्य चर की दृश्यता को स्पष्ट कर सकते हैं। इन संशोधकों की व्याख्या स्पष्ट है और विधियों के लिए शब्दार्थ के साथ संरेखित है:
- निजी - सदस्य चर का उपयोग केवल उस वर्ग के भीतर किया जा सकता है जहां इसे परिभाषित किया गया है।
- संरक्षित - सदस्य चर का उपयोग उस वर्ग में किया जा सकता है जहां इसे परिभाषित किया गया है और उस वर्ग के सभी उपवर्ग।
- सार्वजनिक - सदस्य चर का उपयोग कहीं भी किया जा सकता है। यह वर्ग पदानुक्रम की सीमाओं के बाहर दिखाई देता है जहां इसे परिभाषित किया गया है।
डिफ़ॉल्ट रूप से, सदस्य चर जो स्पष्ट संशोधक से सजाए नहीं गए हैं, वे अभी भी सुरक्षित हैं। हालाँकि, सर्वोत्तम अभ्यास के रूप में, आपको दृश्यता स्पष्ट रूप से निर्दिष्ट करनी चाहिए। जैसा कि हमने पहले वर्णित किया है, जब एक सदस्य चर को सार्वजनिक के रूप में परिभाषित किया जाता है, तो इसे उस वर्ग के बाहर एक्सेस किया जा सकता है जहां इसे परिभाषित किया गया है। इस स्थिति में, आपको एक क्वालीफायर निर्दिष्ट करना होगा जो उस ऑब्जेक्ट को निर्दिष्ट करता है जो चर को होस्ट कर रहा है। क्वालीफायर निर्दिष्ट करने के लिए, डॉट नोटेशन का उपयोग करें, जैसा कि आप विधि कॉल के लिए करते हैं।
निम्न उदाहरण में, फ़ील्ड1 को स्पष्ट इस क्वालीफायर का उपयोग करके एक्सेस किया जाता है। इस मामले में, किसी सदस्य को परिवर्तनशील सार्वजनिक करना एक अच्छा विचार नहीं हो सकता है, क्योंकि यह दृष्टिकोण वर्ग के आंतरिक कामकाज को अपने उपभोक्ताओं के सामने उजागर करता है, और इसलिए वर्ग कार्यान्वयन और उसके उपभोक्ताओं के बीच एक मजबूत निर्भरता पैदा करता है। आपको हमेशा केवल एक अनुबंध पर निर्भर रहने की कोशिश करनी चाहिए, कार्यान्वयन पर नहीं।
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();
}
अनुप्रयोग एक्सप्लोरर में वर्ग तत्व
अनुप्रयोग एक्सप्लोरर में अधिकांश वर्ग नोड्स के अंतर्गत, दो विशेष नोड्स हैं: एक classDeclaration नोड और एक नया नोड। एक 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() को कॉल करें।
निम्न उदाहरण पिछले classDeclaration उदाहरण में 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);
}
कचरा संग्रहण
अंततः रन टाइम के दौरान, अधिकांश ऑब्जेक्ट्स में अब कोई चर नहीं होता है जो उन्हें इंगित करता है। सिस्टम इन वस्तुओं के लिए स्कैन करता है और उन्हें स्मृति से मिटा देता है। मेमोरी स्पेस तब अन्य उपयोगों के लिए उपलब्ध हो जाता है। ऑब्जेक्ट क्लास में एक विधि है जिसे अंतिम रूप दिया गया है। हालाँकि, अंतिम रूप देने की विधि विनाशक नहीं है। रनटाइम कभी भी अंतिम रूप देने की विधि को कॉल नहीं करता है, तब भी जब किसी वस्तु को कचरे के रूप में एकत्र किया जाता है।
सिस्टम कक्षाएं
अनुप्रयोग एक्सप्लोरर में, सिस्टम दस्तावेज़ीकरण>कक्षाओं के अंतर्गत, कर्नेल वर्गों या सिस्टम वर्गों की एक सूची है। सिस्टम कक्षाएं 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 विधियों का उपयोग करता है। फ़ील्डसीएनटी विधि किसी तालिका में फ़ील्ड की संख्या की गणना करती है, जबकि fieldCnt2Id फ़ील्ड नंबर के लिए आईडी लौटाता है। उदाहरण के लिए, आप किसी तालिका में फ़ील्ड संख्या 6 ID 54 है कि जानने के लिए फ़ील्डCnt2Id विधि का उपयोग कर सकते हैं। यह रूपांतरण आवश्यक है, क्योंकि इस बात की कोई गारंटी नहीं है कि तालिका में फ़ील्ड्स की ID लगातार हैं.
// 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), "'";
}
}