השוואת X++ ו- C#‎

הערה

קבוצות עניין של קהילה עברו כעת מ- Yammer Microsoft Viva Engage. כדי להצטרף לקהילת Viva Engage ולהשתתף בדיונים האחרונים, מלא את טופס הגישה לקהילת כספים ופעולות Viva Engage ובחר את הקהילה שאליה ברצונך להצטרף.

מאמר זה משווה תחביר ותכנות של X++ ו- C#‎.

השוואת X++, C# : Hello World

סעיף זה משווה את תוכנית ה- X++ הפשוטה ביותר לתוכנית המקבילה ב- C#‎.

השוואות בין X++ ל- C#‎

הסעיפים הבאים מתארים כמה נקודות דמיון בסיסיות והבדלים בין X++ ל- C#‎.

הדמיון

התכונות הבאות של X++ זהות עבור C#‎:

  • הערות של שורה בודדת (//) והערות מרובות שורות (/* */).
  • == (שווה) אופרטור הקובע אם שני ערכים שווים.
  • != (לא שווה ל) עבור קביעה אם שני ערכים אינם שוות ערך.
  • + (סימן חיבור) עבור שרשור מחרוזת.

ההבדלים

הטבלה הבאה מפרטת תכונות X++ השונות ב- C#‎.

תכונה X++ C#‎ הערות
if והצהרת else תנאי המשפט if מקבל כל סוג של ביטוי שהוא יכול להמיר באופן אוטומטי לבוליאני. דוגמאות נפוצות כוללות ש int - 0 פירושו False, או אובייקט שעבורו Null פירושו False. המשפט if דורש ביטוי בוליאני. מבנה התחביר בנוגע סוגריים מסולסלים וסוגריים זהה בדיוק בין X++ ל- C#‎.
מחרוזת מילולית ניתן להפרד מחרוזת מילולית באמצעות אחת מהשיטות הבאות:
  • זוג תווי מרכאות כפולות (").
  • זוג תווי גרש בודד (').
מחרוזת מילולית חייבת להיות מופרדת באמצעות זוג תווים של מרכאות כפולות ("). עבור X++, תווי המרכאות הכפולות משמשים בדרך כלל להפריד מחרוזות. עם זאת, מומלץ להוסיף מחרוזת עם תווי גרש בודד כאשר המחרוזת חייבת להכיל תו מרכאות כפולות.
תו (תו) type אין סוג או תו char ב- X++. באפשרותך להצהיר str על אורך אחד, אך זו עדיין מחרוזת:
str 1 myString = "a";
יש ב- char C#. לא ניתן להעביר תחילה פרמטר char לפעולת שירות המקלטה string פרמטר, על אף שתחילה ניתן להמיר תחילה את char הפרמטר ל- string. לקבלת מידע נוסף אודות סוגי נתונים של X++, ראה סוגי נתונים פרימיטיביים.
פלט של הודעות X++ מעביר הודעות למשתמש בחלון Infolog. שיטות נפוצות כוללות:
  • משפט ההדפסה:
  • פעולות שירות סטטיות בכיתה Global :
    • כללי::מידע
    • כללי::אזהרה
    • כללי::שגיאה
עבור תוכנית שורת פקודה, ניתן להעביר הודעות לקונסולה. שיטות נפוצות כוללות:
  • Console.Out.WriteLine
  • Console.Error.WriteLine

דוגמאות X++ ו- C#‎

מקטע זה מכיל שתי דוגמאות קוד פשוטות. מדגם אחד נכתב ב- X++, והדוגמה האחרת נמצאת ב- C#. שני הדגימות משיגות את אותה תוצאה. התכונות הבאות של X++ מודגמת:

  • // הערת שורה בודדת
  • /\* \*/ הערה מרובת שורות
  • if הצהרה
  • == מרכזיה
  • != מרכזיה
  • + אופרטור לשרשור מחרוזות
  • כללי::מידע עבור פלט הודעה, עם וללא הקידומת Global::
  • כללי::שגיאה עבור פלט הודעה
  • השימוש בתווים בודדים ובגרשיים כפולים (' ו- ") כמפרידי מחרוזת.

הערה

שיטות העבודה המומלצות היא להשתמש במרכאות כפולות עבור כל מחרוזת שעשויה להיות מוצגת למשתמש.

דוגמה של X++

דוגמת קוד X++ זו היא בצורת משימה. קיים צומת בשם 'משימות' בעץ האובייקטים של היישום (AOT). ניתן להוסיף דוגמה זו תחת הצומת 'משימות' ולאחר מכן ניתן להפעיל את המשימה.

static void JobRs001a_HelloWorld(Args _args)
{
    if (1 == 1) 
    {
        // These two info() calls are identical to the X++ compiler.
        // The second form is the one typically used in X++.
        Global::info("Hello World, 1.");
        info('Hello World, 2.');
    }
    if (1 != 1)
    {
        error("This message will not appear.");
    }
    else
    {
        // These two methods are also from the Global class.
        // The + operator concatenates two strings.
        warning("This is like info, but is for warnings, 3.");
        error("This is like info, but is for errors, 4.");
    }
}
פלט

הנה הפלט מחלון Infolog: הודעה (09:49:48) Hello World, 1. Hello World, 2. פעולה זו דומה למידע, אך היא מיועדת לאזהרות, 3. זה כמו מידע, אך הוא מיועד לשגיאות, 4.

דוגמה ל- C#‎

תוכנית C# הבאה היא שכתוב של תוכנית X++ הקודמת.

using System;
class Pgm_CSharp
{
    static void Main( string[] args )
    {
        new Pgm_CSharp().Rs001a_CSharp_HelloWorld();
    }
    void Rs001a_CSharp_HelloWorld()
    {
        if (1 == 1) 
        {
            Console .Out .WriteLine("Hello World, Explicit .Out , 1.");
            Console .WriteLine("Hello World, Implicit default to .Out , 2.");
        }
        if (1 != 1)
        {
            Console .Error .WriteLine("This message will not appear.");
        }
        else
        {
            Console .Error .WriteLine(".Error is like .Out, but can be for warnings, 3.");
            Console .Error .WriteLine(".Error is like .Out, but is for errors, 4.");
        }
    }
}
פלט

הנה הפלט בפועל לקונסולת C#‎:

Hello World, Explicit .Out, 1. 
Hello World, Implicit default to .Out, 2. 
.Error is like .Out, but can be for warnings, 3. 
.Error is like .Out, but is for errors, 4.

השוואת X++, C# : לולאות

סעיף זה משווה את תכונות הלולאה בין X++ ל- C#‎.

הדמיון

התכונות הבאות זהות ב- X++ וב- C#‎:

  • הצהרות על משתנים של סוג הנתונים הפרימיטיבי ה int. הצהרות עבור סוגים פרימיטיביים אחרים זהות כמעט, אך הסוגים עשויים להיות בעלי שמות שונים.
  • משפט while עבור לולאות.
  • משפט עצירה כדי לצאת בלולאה.
  • המשך משפט כדי לקפוץ לראש לולאה.
  • <= (קטן או שווה) אופרטור השוואה.

ההבדלים

הטבלה הבאה מפרטת תכונות X++ השונות ב- C#‎.

תכונות X++ C#‎ הערות
ההצהרה.for המשפט for זמין עבור לולאות. המשפט C#‎ for שונה במקצת מ- for X++. ב- C# באפשרותך להצהיר על המספר השלם של המונה במשפט for . אך ב- X++ יש להצהיר על המונה מחוץ להצהרה for .
אופרטור ההפרשים המצטברים של ++ . אופרטור של רווחים קבועים ++ זמין ב- X++. אך משתנה int המעוטר ב- ++ יכול לשמש רק כהצהרה, לא כביטוי. לדוגמה, השורות הבאות של קוד X++ לא הידור:
int age=42;
print age++;
עם זאת, השורות הבאות של קוד X++ הידור:
int age=42;
age++; print age;
האופרטור C# ++ גמיש יותר מאשר ב- X++. שורות הקוד הבאות זהות בשתי השפות:
  • ++ myIntger;
  • myInteger++;
אך לשורות הקוד הבאות יש השפעה שונה זו של זו, והן חוקיות רק ב- C#‎:
  • yourInt = ++myInt;
  • yourInt = myInt++;
אופרטור מודולו. ב- X++ אופרטור מודולו מוד. In C# the modulo operator is %. הסימנים של אופרטור מודולו שונים, אך אופן הפעולה שלהם זהה בשתי השפות.
השעיה זמנית של תוכנית קונסולה שכבר התחילה. ההצהרה.pause ב- C#, ניתן להשהות תוכנית שורת פקודה באמצעות שורת הקוד הבאה:
Console.In.Read();
ב- X++ תוכל להמשיך על-ידי לחיצה על לחצן אישור בתיבת דו-שיח מודאלית. ב- C# תוכל להמשיך על-ידי הקשה על לוח מקשים כלשהו בלוח המקשים.
הצגת הודעה. ב- X++, print המשפט מציג הודעה בחלון הדפסה. ב- C# ניתן להציג הודעה בקונסולה באמצעות שורת הקוד הבאה:
Console.WriteLine();
הפונקציה X++ print נמצאת בשימוש רק בעת הבדיקה. תוכנית X++ המשתמשת כמעט print תמיד במשפט pause במקום כלשהו בהמשך הקוד. עבור קוד X++ של ייצור, השתמש בפעולת השירות Global::info במקום ב- print. הפונקציה strfmt משמשת לעתים קרובות יחד עם info. אין סיבה להשתמש לאחר pauseinfo.
תשמיעי צליל. פונקציית צפצוף מבצעת צליל שאתה יכול לשמוע. ב- C# צליל שתוכל לשמוע מונפק על-ידי שורת הקוד הבאה:
Console.Beep();
המשפטים של כל אחד מהם מפיקים צליל קצר.

דוגמאות קוד X++ עבור לולאות משתמשות בפונקציה print להצגת תוצאות. ב- X++ באפשרותך print להשתמש במשפט כדי להציג כל סוג נתונים פרימיטיבי מבלי שתצטרך לבצע קריאה לפונקציות שממירות אותו למחרוזת תחילה. פעולה זו שימושית print במצבי בדיקה מהירה. בדרך כלל נעשה שימוש בפעולת השירות Global::info בתדירות גבוהה יותר מ- print. פעולת info השירות יכולה להציג מחרוזות בלבד. לכן הפונקציה strfmt משמשת לעתים קרובות יחד עם info. מגבלה של print היא שלא ניתן להעתיק את התוכן של חלון ההדפסה ללוח (כגון עם Ctrl+C). Global::info כותב בחלון Infolog, אשר תומך בהעתקה ללוח.

דוגמה 1: The while Loop

בעוד מילת המפתח תומכת בלולאה הן ב- X++ והן ב- C#‎.

דוגמה של X++ לזמן

static void JobRs002a_LoopsWhile(Args _args)
{
    int nLoops = 1;
    while (nLoops <= 88)
    {
        print nLoops;
        pause;
        // The X++ modulo operator is mod.
        if ((nLoops mod 4) == 0)
        {
            break;
        }
        ++ nLoops;
    }
    beep(); // Function.
    pause; // X++ keyword.
} 
פלט

הפלט בחלון X++ Print הוא כדלקמן:

1
2
3
4

C# דוגמה של while

using System;
public class Pgm_CSharp
{
    static void Main( string[] args )
    {
        new Pgm_CSharp().WhileLoops();
    }

    void WhileLoops()
    {
        int nLoops = 1;
        while (nLoops <= 88)
        {
            Console.Out.WriteLine(nLoops.ToString());
            Console.Out.WriteLine("(Press any key to resume.)");
            // Paused until user presses a key.
            Console.In.Read();
            if ((nLoops % 4) == 0) {
                break;
            }
            ++ nLoops;
        }
        Console.Beep();
        Console.In.Read();
    }
}
פלט

פלט הקונסולה מתוכנית C# הוא כדלקמן:

1
(Press any key to resume.)
2
(Press any key to resume.)
3
(Press any key to resume.)
4
(Press any key to resume.)

דוגמה 2: The for Loop

מילת המפתח עבור תומכת בלולאה הן ב- X++ והן ב- C#‎.

דוגמה של X++ עבור

ב- X++ אין אפשרות להצהיר על משתנה המונה כחלק מהצהרת for .

static void JobRs002a_LoopsWhileFor(Args _args)
{
    int ii; // The counter.
    for (ii=1; ii < 5; ii++)
    {
        print ii;
        pause;
        // You must click the OK button to proceed beyond a pause statement.
        // ii is always less than 99.
        if (ii < 99)
        {
            continue;
        }
        print "This message never appears.";
    }
    pause;
}
פלט

הפלט בחלון X++ Print הוא כדלקמן:

1
2
3
4

דוגמה של C# עבור

using System;
public class Pgm_CSharp
{
    static void Main( string[] args )
    {
        new Pgm_CSharp().ForLoops();
    }
    void ForLoops()
    {
        int nLoops = 1, ii;
        for (ii = 1; ii < 5; ii++)
        {
            Console.Out.WriteLine(ii.ToString());
            Console.Out.WriteLine("(Press any key to resume.)");
            Console.In.Read();
            if (ii < 99)
            {
                continue;
            }
            Console.Out.WriteLine("This message never appears.");
        }
        Console.Out.WriteLine("(Press any key to resume.)");
        Console.In.Read();
    }
}
פלט

פלט הקונסולה מתוכנית C# הוא כדלקמן:

1
(Press any key to resume.)
2
(Press any key to resume.)
3
(Press any key to resume.)
4
(Press any key to resume.)
(Press any key to resume.)

השוואת X++, C# : Switch

הן ב- X++ והן ב- C#, משפט המעבר כולל את מקרה מילות המפתח, ההפסקה וברירת המחדל. הטבלה הבאה מפרטת את ההבדלים במשפט המעבר בין X++ ל- C#‎.

תכונה X++ C#‎ הערות
break; בסוף כל בלוק אירוע ב- X++, כאשר בלוק רישיות תואם לערך הביטוי במשפט הבורר, כל בלוקי הרישיות ובלוקי ברירת המחדל האחרים מבוצעים עד לקבלת משפט.break; לא break; נדרשת אף הצהרה במשפט מעבר X++ אךbreak; הצהרות חשובות כמעט בכל המצבים המעשיים. ב- C#, משפט break; נדרש תמיד לאחר המשפטים בבלוק רישיות אובבלוק ברירת מחדל. אם פסוקית מקרה אינה כוללת משפטים בין עצמו לבין פסוקית הרישיות הבאה, break; משפט אינו נדרש בין שני משפטי הרישיות. אנו ממליצים למנוע השמטת break; ההצהרה לאחר חסימת אירוע כלשהי, מכיוון שהיא יכולה לבלבל את המתכנת הבא שעורכים את הקוד.
break; בסוף בלוק ברירת המחדל ב- X++ אין השפעה על הוספת משפט break; בסוף בלוק ברירת המחדל. ב- C# המהדר דורש משפט break; בסוף בלוק ברירת המחדל. לקבלת מידע נוסף, ראה החלפת הצהרות.
רק ערכים קבועים בבלוק רישיות ב- X++ באפשרותך לציין ערך ליטרלי או משתנה בבלוק רישיות. לדוגמה, באפשרותך לכתוב מקרה myIntger:. ב- C# עליך לציין ערך ליטרלי אחד בדיוק בכל בלוק אירוע, ולא מותרים משתנים. אין הערות.
ערכים מרובים בבלוק מקרה אחד ב- X++ באפשרותך לציין ערכים מרובים בכל בלוק רישיות. יש להפריד בין הערכים באמצעות פסיק. לדוגמה, באפשרותך לכתוב case 4,5,myInteger:. ב- C# עליך לציין ערך אחד בדיוק בכל בלוק רישיות. ב- X++ עדיף break; לכתוב ערכים מרובים בבלוק רישיות אחד מאשר להשמיט את המשפט בסוף בלוק רישיות אחד או יותר.

דוגמאות קוד עבור מתג

הסעיפים הבאים מציגים משפטי בורר השוואה ב- X++ וב- C#‎.

דוגמה של מתג X++

דוגמה של הבורר X++ מציגה את האפשרויות הבאות:

  • case iTemp: ולה case (93-90): להראות שהביטויים במקרה אינם מוגבלים בקבועים, כפי שהם ב- C#‎.
  • //break; כדי להראות שהצהרה break; אינה נדרשת ב- X++, על אף שהן כמעט תמיד רצויות.
  • case 2, (93-90), 5: כדי להראות שניתן להציג ביטויים מרובים במשפט מקרה אחד ב - X++.
static void GXppSwitchJob21(Args _args)  // X++ job in AOT &gt; Jobs.
{
    int iEnum = 3;
    int iTemp = 6;
    switch (iEnum)
    {
        case 1:
        case iTemp:  // 6
            info(strFmt("iEnum is one of these values: 1,6: %1", iEnum));
            break;
        case 2, (93-90), str2Int("5"):  // Equivalent to three 'case' clauses stacked, valid in X++.
            //case 2:
            //case (93-90):  // Value after each 'case' can be a constant, variable, or expression; in X++.
            //case str2Int("5"):
            info(strFmt("iEnum is one of these values: 2,3,5: %1", iEnum));
            //break;  // Not required in X++, but usually wanted.
        case 4:
            info(strFmt("iEnum is one of these values: 4: %1", iEnum));
            break;
        default:
            info(strFmt("iEnum is an unforeseen value: %1", iEnum));
            break;
            // None of these 'break' occurrences in this example are required for X++ compiler.
    }
    return;
}

/*** Copied from the Infolog:
Message (02:32:08 pm)
iEnum is one of these values: 2,3,5: 3
iEnum is one of these values: 4: 3
***

דוגמה של החלפת C#‎

דוגמה של הבורר C# מציגה את האפשרויות הבאות:

  • מקרה 1: יש הערה המסבירה שניתן להוסיף ביטויים קבועים בלבד בפסוקית אירוע.
  • break; המשפטים מתרחשים לאחר המשפט האחרון בכל בלוק מקרה הכולל משפטים, כפי שנדרש על-ידי C#‎.
using System;
namespace CSharpSwitch2
{
    class Program
    {
        static void Main(string[] args)  // C#‎
        {
            int iEnum = 3;
            switch (iEnum)
            {
                case 1:  // Value after each 'case' must be a constant.
                case 6:
                    Console.WriteLine("iEnum is one of these values: 1,6: " + iEnum.ToString());
                    break;
                //case 2,3,5:  // In C# this syntax is invalid, and multiple 'case' clauses are needed.
                case 2:
                case 3:
                case 5:
                    Console.WriteLine("iEnum is one of these values: 2,3,5: " + iEnum.ToString());
                    break;
                case 4:
                    Console.WriteLine("iEnum is one of these values: 4: " + iEnum.ToString());
                    break;
                default:
                    Console.WriteLine("iEnum is an unforeseen value: " + iEnum.ToString());
                    break;
                // All 'break' occurrences in this example are required for C# compiler.
            }
          return;
        }
    }
}
/*** Output copied from the console:
>> CSharpSwitch2.exe
iEnum is one of these values: 2,3,5: 3
>>
***/

השוואת X++, C# : רישיות ומפרידים של מחרוזת

סעיף זה משווה את הטיפול במחרוזות עם רישיות מעורבות ב- X++ וב- C#. הוא מסביר גם את מפרידי המחרוזת הזמינים ב- X++.

הדמיון

התכונות הבאות של X++ זהות לתכונות ב- C#‎:

  • קו נטוי הפוך (\) הוא אופרטור ביטול עבור מפרידי מחרוזת.
  • סימן at (@) מסמן את אפקט הבריחה של קו נטוי הפוך כאשר סימן at נכתב מיד לפני תו המרכאות הפתוח של מחרוזת.
  • סימן החיבור (+) הוא אופרטור שרשור המחרוזת.

ההבדלים

תכונות X++ השונות ב- C# מפורטות בטבלה הבאה.

תכונה X++ C#‎ הערות
==אופרטור השוואה לא תלוי: האופרטור == אינו תלוי בהבדלים במתן רישיות של מחרוזות. ב- C#, == האופרטור רגיש להבדלים במתן רישיות של מחרוזות. ב- X++ באפשרותך להשתמש בפונקציה strCmp עבור השוואות תלויות רישיות בין מחרוזות.
מפרידי מחרוזת ב- X++ באפשרותך להשתמש במרכאות בודדות (') או כפולות (") כמפריד המחרוזת.

הערה: בדרך כלל, מומלץ להשתמש במרכאות כפולות עבור מחרוזות שעשויות להיות מוצגות למשתמש. עם זאת, נוח להוסיף מחרוזת עם גרש בודד כאשר תו מרכאות כפולות הוא אחד מהתווים במחרוזת.

ב- C# עליך להשתמש במרכאות כפולות כמפריד המחרוזת. פעולה זו מתייחסת לסוג System.String. ב- X++ וב- C# יש לך אפשרות להטביע מפריד במחרוזת מילולית ולהוות אותו עם .
ב- X++ יש לך גם חלופה להטבעת גרש בודד במחרוזת המופרדת באמצעות מרכאות כפולות (או הפוך), מבלי שתצטרך להשתמש ב- Escape.
מפרידי תווים ל- X++ יש סוג נתוני מחרוזת (str), אך אין סוג תו. ב- C# עליך להשתמש בגרש בודד כמפריד תווים. פעולה זו מתייחסת לסוג System.Char. ב- .NET Framework, System.String אורך אחד הוא סוג נתונים שונה מזה של System.Char תו.

דוגמה 1: רגישות רישיות של האופרטור ==

האופרטורים == ו- != אינם תלויי רישיות ב- X++, אך הם תלויי רישיות ב- C#, כפי שמצוין בדוגמה הבאה.

X++ C#‎ הערות
"HELLO" == "hello"
True ב- X++.
"HELLO" == "hello"
False ב- C#‎.
השוואות רישיות שונות בין X++ ל- C#‎.

דוגמה 2: האופרטור + שרשור מחרוזת

האופרטורים + ו- += משמשים לשרשור מחרוזות הן ב- X++ והן ב- C#, כפי שמוצג בדוגמאות בטבלה הבאה.

X++ C#‎ הערות
myString1 = "Hello" + " world";
התוצאה היא שוויון:
myString1 == "Hello world"
(זהה ל- X++.) הן ב- X++ והן ב- C#, אופן הפעולה של האופרטור + תלוי בסוג הנתונים של האופרנדים שלו. האופרטור משרשר מחרוזות או מוסיף מספרים.
mystring2 = "Hello";
myString2 += " world";
התוצאה היא שוויון: myString2 == "Hello world"
(זהה ל- X++.) הן ב- X++ והן ב- C#, המשפטים הבאים הם שווי ערך:
a = a + b;
a += b;

דוגמה 3: מפרידי מחרוזת מוטבעים ובריחים

ניתן להשתמש בגרשיים בודדים או במרכאות כפולות כדי להוסיף מחרוזות ב- X++. ניתן להשתמש בתו Escape (\) כדי להטביע מפרידים במחרוזת. אלה מוצגים בטבלה הבאה.

X++ C#‎ הערות
myString1 = "They said \"yes\".";
תוצאה:
They said "yes".
(זהה ל- X++.) תו Escape מאפשר לך להטביע מפרידי מחרוזת בתוך מחרוזות.
myString2 = 'They said "yes".';
תוצאה:
They said "yes".
תחביר C# אינו מאפשר הפרדת מחרוזות בין מרכאות בודדות. עבור מחרוזות שהמשתמש עשוי לראות, מומלץ להשתמש בתו Escape במקום בגרשיים בודדים, כפי שמוצג בדוגמה.
myString3 = "They said 'yes'.";
תוצאה:
They said 'yes'.
(זהה ל- X++.) ב- X++, מרכאות בודדות אינן מטופלות כמפרידים אלא אם המחרוזת מתחילה במפריד של גרש בודד. ב- C# לגרש בודד אין משמעות מיוחדת עבור מחרוזות, ולא ניתן להשתמש בו כדי להוסיף מחרוזות. ב- C# תו המירכאות הוא המפריד הנדרש עבור ליטרלים מסוג System.Char. ל- X++ אין סוג נתונים של תו.
str myString4 = 'C';
כאן, המירכאות בודדות כוללות מפריד בין מחרוזות.
char myChar4 = 'C';
כאן תו המרכאות הוא System.Char מפריד, לא System.String מפריד.
ל- X++ אין סוג נתונים שתואם System.Char ל- .NET Framework. מחרוזת X++ המוגבלת לאורך של מחרוזת אחת היא עדיין מחרוזת, ולא סוג נתונים של תו.

דוגמה 4: תו Escape יחיד

דוגמאות שממחישות את תו ביטול יחיד בקלט או בפלט מוצגות בטבלה הבאה.

X++ C#‎ הערות
myString1 = "Red\ shoe";
תוצאה:
Red shoe
מחרוזת ליטרל ב- C# אינה יכולה להכיל את רצף שני התווים של Escape ואחריו רווח, כגון "\ ". מתרחשת שגיאת מהדר. כאשר מהדר X++ נתקל ברצף שני התווים של "\ ", הוא מוחק את תו ביטול יחיד.
myString2 = "Red\\ shoe";
תוצאה:
Red\ shoe
(זהה ל- X++.) בזוג תווי ביטול, הראשונה שלילה את המשמעות המיוחדת של השני.

השוואה: תחביר מערך

קיימים קווי דמיון והבדלים בתכונות ובתחביר עבור מערכים ב- X++ לעומת C#‎.

הדמיון

בסך הכל יש דמיון רב בתחביר ובטיפול במערכים ב- X++ וב- C#. עם זאת, קיימים הבדלים רבים.

ההבדלים

הטבלה הבאה מפרטת את האזורים בתחביר [] עבור מערכים שונים עבור X++ ו- C#‎.

קטגוריה X++ C#‎ הערות
הצהרת מערך מוצהר עם סוגריים מרובעים המצורפים לשם המשתנה. מערך מוצהר עם סוגריים מרובעים המצורפים לסוג הנתונים. int myInts[]; // X++

הערה: מערך X++ אינו יכול להיות פרמטר בפעולת שירות.

int[] myInts; // C#‎

הצהרת תחביר המערך תומך רק בסוגי נתונים פרימיטיביים, כגון int ו- str. התחביר אינו תומך במחלקות או בטבלאות. תחביר המערך תומך בסוגי נתונים ומחלקות פרימיטיביים. ב- X++ באפשרותך להשתמש במערך Array עבור מערך של אובייקטים.
הצהרת X++ מוגבל למערכים של ממדים בודדים (myStrings[8]). C# מוסיף תמיכה עבור מערכים רב-ממדיים (myStrings[8,3]) ולערכים משוננים (myStrings[8][3]). ב- X++ לא יכול להיות מערך של מערכים. עם זאת, קיים תחביר מתקדם להגבלת כמות הזיכרון הפעיל שניתן לצרוך במערך גדול, שנראה כמו התחביר הרב-ממדי ב- C#: int intArray[1024,16];. לקבלת מידע נוסף, ראה מיטובים של ביצועי שיטות עבודה מומלצות: החלפת מערכים לדיסק.
הצהרת ב- X++ מערך הוא מבנה מיוחד, אך הוא אינו אובייקט. ב- C# כל המערכים הם אובייקטים ללא קשר לווריאציות תחביר. ל- X++ יש מחלקת מערך, אך המנגנון המשמשת כברירת מחדל שונה ממערכים שנוצרו באמצעות התחביר []. ב- C# כל המערכים משתמשים באותו מנגנון המשמש תחילה, בין אם תחביר [] System.Array של המחלקה נמצא בשימוש בקוד שלך.
אורך ב- X++ האורך של מערך סטטי בגודל נקבע בתחביר ההצהרה. ב- C# הגודל של מערך נקבע בעת בניית אובייקט המערך. בעת שימוש בתחביר ההצהרה [] ב- X++, אין צורך בהכנה נוספת לפני הקצאת ערכים למערך.
ב- C# עליך להצהיר ולאחר מכן לבנות את המערך לפני הקצאתו.
אורך מערך X++ יכול להכיל אורך דינאמי שניתן להוסיף גם לאחר שהאוכלוסייה החלה. הדבר חל רק כאשר המערך מוצהר ללא מספר בתוך []. הביצועים עשויים להיות איטיים אם אורך המערך הדינאמי גדל פעמים רבות. ב- C# לא ניתן לשנות את האורך של מערך לאחר הגדרת האורך. במקטע הבא של קוד X++, רק המערך myInts דינאמי וגודלו יכול להיות גדול יותר.
int myInts[];
int myBools[5];
myInts[2] = 12;
myInts[3] = 13;
myBools[6] = 26; //Error
אורך באפשרותך לקבל את האורך של מערכים מסוימים באמצעות הפונקציה dimOf . מערכים של C# הם אובייקטים בעלי Length מאפיין. אין הערות.
יצירת אינדקס יצירת אינדקס מערך מבוססת על 1. יצירת אינדקס מערך מבוססת על 0. mtIntArray[0] יגרום לשגיאה ב- X++.
קבוע ב- X++ ערך קבוע מושג באופן מיטבי באמצעות #define מראש. ב- C# באפשרותך לקשט את ההצהרה המשתנה שלך עם מילת המפתח const, כדי להשיג ערך קבוע. ל- X++ אין מילת מפתח של Const . ל- C# אין אפשרות להקצות ערכים למשתנים הנוצרים על-ידי #define מראש.

דוגמאות X++ ו- C#‎

דוגמאות הקוד הבאות מראים כיצד מטפלים במערכים של סוגי נתונים פרימיטיביים. המדגם הראשון הוא ב- X++, והמדגם השני נמצא ב- C#. שתי הדגימות משיגות את אותן תוצאות.

דוגמה של X++

static void JobRs005a_ArraySimple(Args _args)
{
    #define.macroArrayLength(3)
    // Static length.
    str sSports[#macroArrayLength];
    // Dynamic length, changeable during run time.
    int years[];
    int xx;
    Global::warning("-------- SPORTS --------");
    sSports[#macroArrayLength] = "Baseball";
    for (xx=1; xx <= #macroArrayLength; xx++)
    {
        info(int2str(xx) + " , [" + sSports[xx] + "]");
    }
    warning("-------- YEARS --------");
    years[ 4] = 2008;
    years[10] = 1930;
    for (xx=1; xx <= 10; xx++)
    {
        info(int2str(xx) + " , " + int2str(years[xx]));
    }
}
פלט

הפלט ל- Infolog הוא כדלקמן:

Message (14:16:08)
-------- SPORTS --------
1 , []
2 , []
3 , [Baseball]
-------- YEARS --------
1 , 0
2 , 0
3 , 0
4 , 2008
5 , 0
6 , 0
7 , 0
8 , 0
9 , 0
10 , 1930

דוגמה ל- C#‎

using System;
public class Pgm_CSharp
{
    static public void Main( string[] args )
    {
        new Pgm_CSharp().ArraySimple();
    }
    private void ArraySimple()
    {
        const int const_iMacroArrayLength = 3;
        // In C# the length is set at construction during run.
        string[] sSports;
        int[] years;
        int xx;
        Console.WriteLine("-------- SPORTS --------");
        sSports = new string[const_iMacroArrayLength];
        sSports[const_iMacroArrayLength - 1] = "Baseball";
        for (xx=0; xx < const_iMacroArrayLength; xx++)
        {
            Console.WriteLine(xx.ToString() + " , [" + sSports[xx] + "]");
        }
        Console.WriteLine("-------- YEARS --------");
        // In C# you must construct the array before assigning to it.
        years = new int[10];
        years[ 4] = 2008;
        years[10 - 1] = 1930;
        for (xx=0; xx < 10; xx++)
        {
            Console.WriteLine(xx.ToString() + " , [" + years[xx].ToString() + "]");
        }
    }
} // EOClass
פלט

הפלט מתוכנית C# למסוף שורת הפקודה הוא כדלקמן:

-------- SPORTS --------
0 , []
1 , []
2 , [Baseball]
-------- YEARS --------
0 , [0]
1 , [0]
2 , [0]
3 , [0]
4 , [2008]
5 , [0]
6 , [0]
7 , [0]
8 , [0]
9 , [1930]

תכונות X++ נוספות, כגון מערך

הגורם המכיל הוא סוג נתונים מיוחד הזמין ב- X++. הוא עשוי להיחשב לדומה למערך, או דומה לאוסף List .

השוואה: אוספים

ביישום כספים ופעולות, באפשרותך להשתמש בשיעור האיסוף של X++ List . ל- .NET Framework המשמש ב- C# יש כיתה דומה בשם System.Collections.Generic.List.

השוואת השימוש במחלקות רשימה

הטבלה הבאה משווה שיטות בכיתה X++ List לשיטות ב- System.Collections.Generic.List מתוך .NET Framework ו- C#‎.

תכונה X++ C#‎ הערות
הצהרה על אוסף List myList; List<string> myList; הצהרת X++ אינה כוללת את סוג הרכיבים שיש לאחסן.
הצהרת באיטראטור ListIterator iter
ListEnumerator enumer;
IEnumerator<string> iter; ב- X++ האובייקט ListIterator כולל פעולות שירות שניתן לבצע ופריטים insertdelete מ- List. ל- X++ ListEnumerator אין אפשרות לשנות את התוכן של List. ב- X++ ListEnumerator האובייקט נוצר תמיד באותה רמה כמו List. זה לא תמיד נכון עבור ListIterator.
השגת Iterator new ListIterator (myList)
myList.getEnumerator()
myList.GetEnumerator() הן ב- X++ והן ב- C#, לאובייקט List יש פעולת שירות getter עבור מונה משויך.
בנאי new List(Types::String) new List<string>() מידע אודות סוג האובייקטים שיש List לאחסן בתוך המחלקות ניתן לבונים הן ב- X++ והן ב- C#‎.
מעדכן נתונים Enumerator – הספירה הופכת ללא חוקית אם פריטים כלשהם ב- מתווספים List או מוסרים.
Iterator – לאיטראטור יש פעולות שירות המוסףות וממחקות פריטים מ- List. ה- Iterator נשאר חוקי.
Enumerator – הספירה הופכת ללא חוקית אם פריטים כלשהם ב- מתווספים List או מוסרים. ספירות הופכות ללא חוקיות לאחר הוספה או מחיקה של Listפריטים מ- , הן ב- X++ והן ב- C#‎.
מעדכן נתונים ב- X++ List הכיתה כוללת שיטות להוספת פריטים בתחילת הרשימה או בסוף הרשימה. ב- C#‎ List הכיתה כוללת שיטות להוספת חברים בכל מיקום ברשימה. הוא כולל גם שיטות להסרת פריטים מכל מיקום. In X++ items can be removed from the List only by a iterator.

דוגמה 1: הצהרה על רשימה

דוגמאות הקוד הבאות הן ב- X++ וב- C# שמכריזות על List אוספים.

// X++
List listStrings ,list2 ,listMerged;
ListIterator literator;
// C#‎
using System;
using System.Collections.Generic;
List<string> listStrings ,list2 ,listMerged; IEnumerator<string> literator;

דוגמה 2: בניית רשימה

בשתי השפות, יש לציין את סוג הפריטים שיש לציין בחנויות האוסף במועד הבנייה. עבור סוגי מחלקה, ל- X++ אין אפשרות לקבל ספציפיות יותר מאשר אם הסוג הוא מחלקה (Types::Class). דוגמאות הקוד הבאות הן ב- X++ וב- C#‎.

// X++
listStrings = new List( Types::String );
// C#‎
listStrings = new List<string>;

דוגמה 3: הוספת פריטים לרשימה

הן ב- X++ והן ב- C#, האוסף מספק שיטה להוספת פריט לסוף האוסף, ולהוספת פריט להתחלה. ב- C# האוסף מספק שיטה להוספה בכל נקודה באוסף בהתבסס על ערך אינדקס. ב- X++ איטראטור אוסף יכול להוסיף פריט במיקום הנוכחי שלו. דוגמאות הקוד הבאות הן ב- X++ וב- C#‎.

// X++
listStrings.addEnd ("StringBB."); 
listStrings.addStart ("StringAA.");
// Iterator performs a midpoint insert at current position. 
listIterator.insert ("dog");
// C#‎
listStrings.Add ("StringBB."); 
listStrings.Insert (0 ,"StringAA.");
// Index 7 determines the insertion point.
listStrings.Insert (7 ,"dog");

דוגמה 4: חזרה דרך רשימה

הן X++ והן C# כוללים מחלקות איטראטור שניתן להשתמש בהן כדי לעבור בין הפריטים באוסף, כפי שמוצג בדוגמאות הבאות.

// X++
literator = new ListIterator (listStrings); 
// Now the iterator points at the first item.

// The more method answers whether 
// the iterator currently points 
// at an item. 
while (literator.more()) 
{ 
    info(any2str (literator.value())); 
    literator.next(); 
}
// C#‎
literator = listStrings .GetEnumerator(); 
// Now enumerator points before the first item, not at the first item.

// The MoveNext method both advances the item pointer, and 
// answers whether the pointer is pointing at an item. 
while (literator.MoveNext()) 
{ 
    Console.WriteLine (literator.Current); 
}

דוגמה 4b: foreach ב- C#‎

ב- C#‎ מילת המפתח foreach משמשת לעתים קרובות כדי לפשט את המשימה של איטראציה ברשימה. דוגמת הקוד הבאה מתנהגת בדיוק כמו בדוגמה הקודמת של C#‎.

foreach (string currentString in listStrings)
{ 
    Console.WriteLine(currentString);
}

דוגמה 5: מחיקת הפריט השני

דוגמאות הקוד הבאות מוחקות את הפריט השני מהאוסף. ב- X++ נדרש איטראטור. ב- C# האוסף עצמו מספק את השיטה להסרת פריט.

// X++
literator.begin(); 
literator.next(); 
literator.delete();
// C#‎
listStrings.RemoveAt(1);

דוגמה 6: שילוב שני אוספים

דוגמאות הקוד הבאות משלבות את התוכן של שני אוספים לאחד.

// X++
listStrings = List::merge(listStrings ,listStr3);
// Or use the .appendList method:
listStrings.appendList (listStr3);
// C#‎
listStrings.InsertRange(listStrings.Count ,listStr3);

השוואה: אוספי מפתחות עם ערכים

ביישום כספים ופעולות, באפשרותך להשתמש בשיעור Map האיסוף. האוסף Map מכיל זוגות ערכים, את ערך המפתח בתוספת ערך נתונים. זה דומה למחלקה .NET Framework בשם System.Collections.Generic.Dictionary.

הדמיון

הרשימה הבאה מתארת קווי דמיון בין X++ ל- C# בנוגע לאוספי שלהם המאחסנים זוגות של ערכי מפתח:

  1. שניהם מונעים מקשים כפולים.
  2. שתיהן משתמשות במונה (או באטראטור) כדי לעבור בלולאה בין הפריטים.
  3. שני אובייקטי אוסף של ערכי מפתח בנויים עם ייעוד של הסוגים המאוחסנים כמפתח וערך.
  4. שניהם יכולים לאחסן אובייקטים של מחלקה, שאינם מוגבלים לאחסון פרימיטיביים כגון int.

ההבדלים

הטבלה הבאה מתארת את ההבדלים בין X++ ל- C# בנוגע למחלקות האוספים שלהם המאחסנים זוגות של ערכי מפתח:

תכונה X++ C#‎ הערות
מפתחות כפולים ב- X++ המחלקה Mapinsert מונעת מקשים כפולים על-ידי טיפול משתמע בקריאה לפעולת השירות שלה כפעולה כדי לעדכן רק את הערך המשויך למפתח. ב- C#‎ Dictionary הכיתה מחזירה חריגה כאשר אתה מנסה להוסיף מפתח כפול. מקשים כפולים נמנעים בשתי השפות, אם כי בטכניקות שונות.
מחיקת פריטים ב- X++ delete פעולת השירות באובייקט איטראטור משמשת להסרת זוג ערכי מפתח לא רצוי מ- Map. ב- C# למחלקה Dictionary יש remove שיטה. בשתי השפות, מונה אינו חוקי אם ספירת הפריטים באוסף משתנה במהלך חיי הספירה.

דוגמה 1: הצהרה על Key-Value חדש

בשתי השפות, יש לציין את סוג הפריטים שיש לציין באוסף ערכי המפתח. ב- X++ הסוג מצוין בעת הבנייה. ב- C# הסוג מצוין הן במועד ההצהרה והן במועד הבנייה. דוגמאות הקוד הבאות הן ב- X++ וב- C#‎.

// X++
Map mapKeyValue;
MapEnumerator enumer;
MapIterator mapIter;
// C#‎
Dictionary<int,string> dictKeyValue;
IEnumerator<SysCollGen.KeyValuePair<int,string>> enumer;
KeyValuePair<int,string> kvpCurrentKeyValuePair;

דוגמה 2: בניית האוסף

בשתי השפות, סוג הפריטים שאוסף ערכי המפתח מאחסן שצוינו במהלך הבנייה. עבור סוגי מחלקה, ל- X++ אין אפשרות לקבל ספציפיות יותר מאשר אם הסוג הוא מחלקה (Types::Class). דוגמאות הקוד הבאות הן ב- X++ וב- C#‎.

// X++
mapKeyValue = new Map(Types::Integer, Types::String);
// C#‎
dictKeyValue = new Dictionary<int,string>();

דוגמה 3: הוספת פריט לאוסף

כמעט אין הבדל באופן שבו פריט נוסף לאוסף ערכי מפתח ב- X++ וב- C# כפי שמוצג בדוגמאות הקוד הבאות.

// X++
mapKeyValue.insert(xx ,int2str(xx) + “_Value”);
// C#‎
dictKeyValue.Add(xx ,xx.ToString() + “_Value”);

דוגמה 4: Iterate Through a Key-Value Collection

ספירות משמשות לצורך מעבר בלולאה בין אוספי ערכי המפתח הן ב- X++ והן ב- C# כפי שמוצג בדוגמאות הקוד הבאות.

// X++ 
enumer = mapKeyValue.getEnumerator();
while (enumer.moveNext())
{
    iCurrentKey = enumer.currentKey();
    sCurrentValue = enumer.currentValue();
    // Display key and value here.
}
// C#‎
enumer = dictKeyValue.GetEnumerator();
while (enumer.MoveNext())
{
    kvpCurrentKeyValuePair = enumer.Current;
    // Display .Key and .Value properties=
    // of kvpCurrentKeyValuePair here.
}

דוגמה 5: עדכון הערך המשויך למפתח

התחביר שונה מאוד בין שתי השפות עבור עדכון של הערך המשויך למפתח נתון. דוגמאות הקוד העדכני מיועדות למפתח 102.

// X++
mapKeyValue.insert(
    102 ,
    ”.insert(), Re-inserted” + ” key 102 with a different value.”);
// C#‎
dictKeyValue[102] = 
    “The semi-hidden .item property in C#, Updated the value for key 102.”;

דוגמה 6: מחיקת פריט אחד

התחביר שונה מאוד בין שתי השפות כדי למחוק זוג אחד של ערכי מפתח מאוסף, תוך כדי חזרה באמצעות חברי האוסף. דוגמאות קוד עבור המפתח 102 מוצגות להלן.

// X++
mapIter = new MapIterator(mapKeyValue);
//mapIter.begin();
while (mapIter.more())
{
    iCurrentKey = mapIter.key();
    if (104 == iCurrentKey)
    {
        // mapKeyValue.remove would invalidate the iterator.
        mapIter.delete();
        break;
    }
    mapIter.next();
}
// C#‎
dictKeyValue.Remove(104);

השוואה: חריגות

קיימים כמה נקודות דמיון, אך הבדלים רבים כאשר אנו משווים אופן פעולה הקשור לחריגה בין X++ ל- C#. מילות המפתח נסה, תלכודותזרוק מילות מפתח יתנהלו באופן זהה ב- X++ וב- C#. אך סוגי החריגים שנזרקה ותפסו שונים עבור שתי השפות.

הדמיון

קווי הדמיון בין X++ ל- C# בנוגע לתכונות החריגות שלהם כוללים את הדוגמאות הבאות:

  • שתי השפות כוללות את אותה מילת מפתח של ניסיון.
  • לשניהם יש אותה מילת מפתח לקליט .
  • שניהם זמינים עבור משפט catch שאינו מציין חריגה מסוימת. משפט catch כזה תופס את כל החריגים להגיע אליו.
  • לשניהם יש מילת מפתח זהה.

ההבדלים

הבדלים הקשורים לחריגה בין X++ ל- C# מתוארים בטבלה הבאה.

תכונה X++ C#‎ הערות
נסה שנית קפיצה להוראה הראשונה בבלוק נסה המשויך . לקבלת מידע נוסף, ראה טיפול בחריגים עם ניסיון וקליטת מילות מפתח. ניתן להשתמש בפונקציונליות של מילת המפתח לניסיון חוזר בקוד C#, אך אין מילת מפתח תואמת. רק ל- X++ יש מילת מפתח לניסיון חוזר. ל- C# אין פריטים המקבילים. לקבלת מידע נוסף, ראה השוואת X++, C# : נסה שנית אוטומטית לאחר חריגה.
סוף סוף מילת finally המפתח נתמכת ומופיעה אחרי try מילות catch המפתח. מילת המפתח לסיום מסמן בלוק קוד שמופיע לאחר הנסיון וקליטת בלוקים. לבסוף יוצאו להורג ללא קשר לשאלה אם יוצאים מן הכלל יתווכו או ייתפסו. סמנטיקה זו זהה למנטיקה ב- C#‎.
חריגות ספציפיות ב- X++ חריג הוא רכיב Exception של ה enum, כגון Error, Deadlock או CodeAccessSecurity. אף חריגה אינה יכולה להכיל חריגה אחרת. ב- C# חריגה היא מופע של מחלקת System.Exception הבסיס, או כל מחלקה יורשת אותה. ניתן לכלול חריגה במאפיין של InnerException החריגה שהוזרקה. ב- X++ כל חריגה שנזרקה היא ערך של ספירת החריגה. לקבלת מידע נוסף, ראה ספירת חריגים.
הודעת חריגה ב- X++ ההודעה שנוצרת כאשר חריגה מופעלת זמינה רק ב- Infolog, וההודעה אינה קשורה ישירות לחריגה. ב- C# ההודעה היא Message החבר באובייקט System.Exception . ב- X++ שיטת Global::error היא מנגנון המציג הודעות חריגה ב- Infolog. לקבלת מידע נוסף, ראה טיפול בחריגים עם ניסיון וקליטת מילות מפתח.
תנאי חריגה ב- X++ מתרחשת שגיאה בעת קריאה לפעולת שירות של מופע במשתנה אובייקט שעדיין לא הוקצה לו דבר. עם זאת, לא הועלה חריגה יחד עם שגיאה זו. לכן, catch אף בלוק לא יכול לקבל שליטה גם אם המשתנה שלא הוקצה נמצא בשימוש שגוי בבלוק try . בדוגמה הבאה של הקוד, box4.toString();catch השגיאה שנגרמה על-ידי הקוד אינה לגרום לפקד לעבור לבלוק כלשהו: DialogBox box4;try { box4.toString();info("toString did not error, but expected an error."); } catch (חריגה::שגיאה) // ערך ללא חריגה תופס זאת. אני לא יודע מה לעשות עם זה. info("Invalid use of box4 gave control to catch, unexpected."); ב- C# a System.NullReferenceException מועלה כאשר משתנה שלא אותחל מטופל כהפניה לאובייקט. עשויים להיות כמה הבדלים אחרים בתנאים הגורמת לחריגים.
עסקאות SQL ב- X++ כאשר מתרחשת חריגת SQL בטרנזקציית ttsBegin - ttsCommit , אף משפט catch בתוך בלוק הטרנזקציה לא יכול לעבד את החריגה. ב- C# בלוק catch בתוך טרנזקציית SQL יכול לתפוס את החריגה.

דוגמאות

התכונות הבאות של X++ מודגמת:

  • נסה מילת מפתח.
  • לכוד מילת מפתח.
  • אופן הפעולה לאחר חריגה::שגיאה מתרחשת.

דוגמה של X++

// X++
static void JobRs008a_Exceptions(Args _args)
{
    str sStrings[4];
    int iIndex = 77;
    try
    {
        info("On purpose, this uses an invalid index for this array: " + sStrings[iIndex]);
        warning("This message doesn't appear in the Infolog," + " it's unreached code.");
    }
    // Next is a catch for some of the values of
    // the X++ Exception enumeration.
    catch (Exception::CodeAccessSecurity)
    {
        info("In catch block for -- Exception::CodeAccessSecurity");
    }
    catch (Exception::Error)
    {
        info("In catch block for -- Exception::Error");
    }
    catch (Exception::Warning)
    {
        info("In catch block for -- Exception::Warning");
    }
    catch
    {
        info("This last 'catch' is of an unspecified exception.");
    }
    //finally
    //{
    //    //Global::Warning("'finally' is not an X++ keyword, although it's in C#.");
    //}
    info("End of program.");
}
פלט

הנה הפלט מחלון Infolog:

Message (18:07:24)
Error executing code: Array index 77 is out of bounds.
Stack trace
(C)\Jobs\JobRs008a_Exceptions - line 8
In catch block for -- Exception::Error
End of program.

דוגמה ל- C#‎

תוכנית C# הבאה היא שכתוב של תוכנית X++ הקודמת.

// C#‎
using System;
public class Pgm_CSharp
{
    static void Main( string[] args )
    {
        new Pgm_CSharp().Rs008a_CSharp_Exceptions();
    }
    void Rs008a_CSharp_Exceptions()
    {
        //str sStrings[4];
        string[] sStrings = new string[4];
        try
        {
            Console.WriteLine("On purpose, this uses an invalid index for this array: " + sStrings[77]);
            Console.Error.WriteLine("This message doesn't appear in the Infolog, it's unreached code.");
        }
        catch (NullReferenceException exc)
        {
            Console.WriteLine("(e1) In catch block for -- " + exc.GetType().ToString() );
        }
        catch (IndexOutOfRangeException exc)
        {
            Console.WriteLine("(e2) In catch block for -- " + exc.GetType().ToString() );
        }
        // In C#, System.Exception is the base of all
        // .NET Framework exception classes.
        // No as yet uncaught exception can get beyond
        // this next catch.
        catch (Exception exc)
        {
            Console.WriteLine("This last 'catch' is of the abstract base type Exception: "
                + exc.GetType().ToString());
        }
        // The preceding catch of System.Exception makes this catch of
        // an unspecified exception redundant and unnecessary.
        //catch
        //{
        //    Console.WriteLine("This last 'catch' is"
        //        + " of an unspecified exception.");
        //}
        finally
        {
            Console.WriteLine("'finally' is not an X++ keyword, although it's in C#.");
        }
        Console.WriteLine("End of program.");
    }
} // EOClass
פלט

הנה הפלט לקונסולת C#‎:

(e2) In catch block for -- System.IndexOutOfRangeException
'finally' is not an X++ keyword, although it's in C#‎.
End of program.

השוואה: ניסיון חוזר אוטומטי לאחר חריגה

לעתים ניתן לכתוב קוד בבלוק קליט שפותר את הגורם לחריגה שמתרחשת במהלך זמן ריצה. X++ מספק מילת מפתח לניסיון חוזר שניתן להשתמש בה רק בתוך בלוק catch . מילת המפתח 'נסה שנית' מאפשרת לתוכנית לקפוץ בחזרה לתחילת בלוק 'נסה' לאחר שהבעיה תוקנה על-ידי קוד בבלוק ה- catch. ל- C# אין מילת מפתח לניסיון חוזר. עם זאת, ניתן לכתוב קוד C# כדי לספק אופן פעולה שווה ערך.

דוגמאות קוד עבור ניסיון חוזר

התוכנית לדוגמה הבאה של X++ גורמת לחריגה::שגיאה להיות מופעלת. מצב זה מתרחש כאשר הוא מנסה לקרוא לראשונה רכיב ממערך sStrings באמצעות ערך אינדקס לא חוקי. כאשר החריגה נתפסת, פעולה מתקן היא ננקטת במהלך זמן ריצה בתוך בלוק catch . משפט הניסיונות החוזרים קופץ בחזרה להצהרה הראשונה בבלוק נסה . איטרציה שניה זו פועלת מבלי להיתקל בחריגה כלשהי.

static void JobRs008b_ExceptionsAndRetry(Args _args)
{
    str sStrings[4];
    str sTemp;
    int iIndex = 0;

    sStrings[1] = "First array element.";
    try
    {
        print("At top of try block: " + int2str(iIndex));
        sTemp = sStrings[iIndex];
        print( "The array element is: " + sTemp );
    }
    catch (Exception::Error)
    {
        print("In catch of -- Exception::Error (will retry)." + " Entering catch.");
        ++iIndex;
        print("In catch of -- Exception::Error (will retry)." + " Leaving catch.");
        // Here is the retry statement.
        retry;
    }
    print("End of X++ retry program.");
    pause;
}

פלט

להלן הפלט של חלון ההדפסה:

At top of try block: 0
In catch of -- Exception::Error (will retry). Entering catch.
In catch of -- Exception::Error (will retry). Leaving catch.
At top of try block: 1
The array element is: First array element.
End of X++ retry program.

דוגמה ל- C#‎

דוגמת ה- C# הבאה אינה תרגום שורה אחר שורה ממדגם X++ הקודם. במקום זאת, לתוכנית C# יש מבנה שונה כך שהיא מחקה את אופן הפעולה של מילת המפתח לניסיון חוזר שתוכנית X++ מסתמכת עליו. בלוקים שלניסיון וקליטתם נמצאים בפעולת שירות שנקראת. המשתנים המשמשים בבלוק נסה מאוחסנים בפעולת השירות של המתקשר. פעולת השירות של המתקשר מעבירה את המשתנים כפרמטרים המעוטרים במילת המפתח ref , כך שניתן לתקן את הערכים שלהם בתוך בלוק ה- catch של פעולת השירות שנקראה. פעולת השירות שנקראת לוכדת את כל החריגים ומחזירה ערך בוליאני כדי לתקשר בחזרה עם המתקשר אם נדרשת שיחה נוספת.

// C#‎
using System;
public class Pgm_CSharp
{
    static void Main(string[] args)
    {
        new Pgm_CSharp() .Rs008b_CSharp_ExceptionsAndRetry();
    }
    void Rs008b_CSharp_ExceptionsAndRetry() // Caller
    {
        int iIndex = -1
            , iNumRetriesAllowed = 3;
        bool bReturnCode = true; // Means call the callee method.
        for (int xx=0; xx <= iNumRetriesAllowed; xx++)
        {
            if (bReturnCode)
            {
                bReturnCode = this.Rs008b_CSharp_ExceptionsAndRetry_Callee(ref iIndex);
            }
            else
            {
                break;
            }
        }
        Console.WriteLine("End of C# caller method.");
    }
    
    private bool Rs008b_CSharp_ExceptionsAndRetry_Callee(ref int iIndex)
    {
        bool bReturnCode = true; // Means call this method again.
        string[] sStrings = new string[4];
        string sTemp;
        sStrings[0] = "First array element.";
        try
        {
            Console.WriteLine("At top of try block: " + iIndex.ToString());
            sTemp = sStrings[iIndex];
            Console.WriteLine( "The array element is: " + sTemp );
            bReturnCode = false; // Means do not call this method again.
        }
        catch (Exception)
        {
            Console.WriteLine("In catch of -- Exception. Entering catch.");
            ++iIndex; // The 'ref' parameter in C#‎.
            Console.WriteLine("In catch of -- Exception. Leaving catch.");
            //retry;
            // In C# we let the caller method do the work
            // that the retry keyword does in X++.
        }
        Console.WriteLine("End of C# callee method.");
        return bReturnCode;
    }
}

פלט

הנה הפלט לקונסולה:

At top of try block: -1
In catch of -- Exception. Entering catch.
In catch of -- Exception. Leaving catch.
End of C# callee method.
At top of try block: 0
The array element is: First array element.
End of C# callee method.
End of C# caller method.

השוואה: אופרטורים

מקטע זה משווה את האופרטורים בין X++ ל- C#‎.

אופרטורים של הקצאה

הטבלה הבאה מציגה את ההבדלים בין אופרטורים של הקצאה ב- X++ וב- C#‎.

X++ ו- C#‎ ההבדלים
= ב- X++ אופרטור זה גורם להמרה משתמעת בכל פעם שמתרחש אובדן דיוק, כגון הקצאה מ- int64 ל- int. אך ב- C# המטלה גורמת לש שגיאת הידור.
+= ו- -= ההבדל היחיד הוא באופרטורים אלה ב- C# משמשים גם למניפולציה של נציגים.
++ ו- -- אלה אופרטורים של ההפרשים המצטברים וההפרשים בשתי השפות. השורה הבאה זהה בשתי השפות:
++myInteger;
אך ב- X++ שני אופרטורים אלה מיועדים במשפטים, ולא עבור ביטויים. לכן, הקווים הבאים יוצרים שגיאות קומפילציה ב- X++:
myStr = int2str(++myInteger);
myIntA = myIntBB++;

אופרטורים אריתמטיים

הטבלה הבאה מפרטת את האופרטורים החשבוניים.

X++ ו- C#‎ ההבדלים
* בתור אופרטור ההכפלה, אין הבדלים.

הערה: הכוכבית משמשת גם במשפטי SQL שהם חלק מהשפה של X++ . במשפטי SQL אלה, הכוכבית יכולה להיות גם אחת מהאפשרויות הבאות:

  • תו כללי המציין שיש להחזיר את כל העמודות.
  • תו כללי עבור תווים במחרוזת הנמצאת בשימוש במשפט Like .
/ אופרטור חילוק זהה ב- X++ וב- C#‎.
MOD עבור פעולות מודולו, ההבדל היחיד הוא % הסימן משמש ב- C#‎.
+ אופרטור החיבור זהה ב- X++ וב- C#. סימן החיבור משמש גם לשרשור מחרוזת. אופרטור זה מוסיף מספרים ומשרשר מחרוזות בשתי השפות.
- אופרטור חיסור זהה ב- X++ וב- C#‎.

אופרטורים לפי סיביות

הטבלה הבאה משווה את האופרטורים לפי סיביות בין X++ ל- C#‎.

X++ ו- C#‎ ההבדלים
<< אופרטור המשמרת השמאלי זהה ב- X++ וב- C#‎.
>> אופרטור המשמרת הימני זהה ב- X++ וב- C#‎.
~ האופרטור NOT לפי סיביות זהה ב- X++ וב- C#‎.
& האופרטור הבינארי AND זהה ב- X++ וב- C#‎.
^ האופרטור הבינארי XOR זהה ב- X++ וב- C#‎.

אופרטורים יחסיים

האופרטורים היחסיים הבאים זהים ב- X++ וב- C#‎:

  • ==
  • <=
  • <=
  • >
  • <
  • !=
  • &&
  • ||
  • !
  • ? :

השוואה: אירועים

קיימים כמה הבדלים באופן היישום של תבנית עיצוב האירוע ב- X++ ו- C#. לקבלת מידע נוסף, ראה מינוח אירוע ומלות מפתח.

השוואה בין אירועים בין X++ ל- C#‎

קיימים הבדלים באופן שבו נציגים משמשים עבור אירועים ב- X++ לעומת C#‎.

מושג X++ C#‎ הערות
נציג ב- X++, ניתן להצהיר על נציג רק כחבר בכיתה. נציג אינו יכול להיות חבר בטבלה. כל הנציגים הם חברי מופע מהמחלקה שלהם, ולא חברים סטטיים . לא ניתן להשתמש בצירוף גישה בהצהרת נציג, מאחר שכל הנציגים הם חברים מוגנים . לכן, ניתן להציג את האירוע רק באמצעות קוד באותה מחלקה שבה הנציג חבר. עם זאת, החריג היחיד לאופי הפרטי של נציג הוא שקוד מחוץ לכיתה שלו יכול לפעול על הנציגים באמצעות האופרטורים += ו- -=. ב- C#, כל נציג הוא סוג, בדיוק כפי שכל כיתה היא סוג. נציג מוצהר באופן עצמאי מכל מחלקה. ללא מילת המפתח של האירוע, באפשרותך להגדיר נציג כסוג פרמטר בפעולת שירות, בדיוק כפי שניתן להגדיר מחלקה כסוג פרמטר. באפשרותך לבנות מופע של נציג להעביר עבור ערך הפרמטר. ב- X++, כל כיתה היא מסוג, אך אף נציג אינו מסוג. לא ניתן לבנות מופע של נציג. נציג אינו יכול להיות פרמטר עבור פעולת שירות. עם זאת, באפשרותך ליצור מחלקה הכוללת חבר נציג, ובאפשרותך להעביר מופעים של המחלקה כסרכי פרמטרים. לקבלת מידע נוסף, ראה מילות מפתח של X++ .
אירוע בקוד X++, אירוע הוא אחת מהאפשרויות הבאות:
  • קריאה מפורשת לנציג.
  • ההתחלה או הסוף של פעולת שירות.
אין מילת מפתח של אירוע ב - X++.
ב- C#, מילת המפתח של האירוע משמשת להצהיר על סוג נציג כחבר בכיתה. ההשפעה של מילת המפתח של האירוע היא להפוך את הנציג מוגן, אך עדיין נגיש עבור האופרטורים += ו- -=. באפשרותך להירשם כמנוי לשיטות המטפל באירועים לאירוע באמצעות האופרטור +=. נציג יכול להיות שימושי ללא מילת המפתח של האירוע, כשיטה להעברת מצביע פונקציה בפרמטר לפעולת שירות. ניתן להירשם כמנוי לאירועים אוטומטיים המתרחשים לפני תחילת פעולת שירות, ולאחר סיום פעולת שירות, רק באמצעות AOT.
אופרטורים של += ו- -= ב- X++, עליך להשתמש באופרטור += כדי להירשם כמנוי לנציג. האופרטור -= לבטל מנוי לפעולת שירות מנציג. ב- C#, עליך להשתמש באופרטור += כדי להירשם כמנוי לאירוע, או לנציג שאינו בשימוש עם מילת המפתח של האירוע. הנציג מכיל הפניה לכל האובייקטים בעלי שיטות שנרשמו כמנוי לנציג. אובייקטים אלה אינם זכאים לאיסוף אשפה בזמן שהנציג מחזיק בהפניות אלה.
eventHandler ב- X++, מילת המפתח eventHandler נדרשת כאשר אתה משתמש באופרטור += או -= כדי להירשם כמנוי או לבטל מנוי לפעולת שירות מנציג. System.EventHandler הוא סוג נציג ב- .NET Framework. מונח זה נמצא בשימוש שונה ב- X++ מאשר ב- C# או ב- .NET Framework. לקבלת מידע נוסף, ראה מילות מפתח של X++ .

דוגמה של X++

הדברים החשובים שיש לציין הם בדוגמה הבאה ב- X++ :

  • לנציג XppClass יש חבר נציג בשם myDelegate.

    הערה

    ה- AOT מכיל צומת עבור הנציג. הצומת ממוקם ב- AOT > Classes > XppClass > myDelegate. ניתן למצוא מספר צמתי מטפל באירועים תחת צומת myDelegate. לא ניתן להסיר את המטפלים באירועים המיוצגים על-ידי צמתים ב- AOT באמצעות האופרטור -= במהלך זמן ריצה.

  • נדרשים {} בסוגריים המסולסלים בסוף הצהרת הנציג, אך לא ניתן לכלול בהם קוד.

  • לנציג XppClass יש שתי שיטות שחתימות הפרמטרים שלה תואמות לנציג. שיטה אחת היא סטטית.

  • שתי השיטות התואמות מתווספות לנציג באמצעות האופרטור += ומלת המפתח eventHandler . הצהרות אלה אינן קוראות לשיטות המטפל באירועים, המשפטים מוסיפים את השיטות לנציג בלבד.

  • האירוע מועלה על-ידי קריאה אחת לנציג.

  • ערך הפרמטר שהועבר לנציג מתקבל על-ידי כל פעולת שירות של מטפל באירועים.

  • משימת X++ הקצרה בחלק העליון של הדוגמה מתחילה את המבחן.

// X++
// Simple job to start the delegate event test.
static void DelegateEventTestJob()
{
    XppClass::runTheTest("The information from the X++ job.");
}
// The X++ class that contains the delegate and the event handlers.
class XppClass
{
    delegate void myDelegate(str _information)
    {
    }
    public void myEventSubscriberMethod2(str _information)
    {
        info("X++, hello from instance event handler 2: " + _information);
    }
    static public void myEventSubscriberMethod3(str _information)
    {
        info("X++, hello from static event handler 3: " + _information);
    }
    static public void runTheTest(str _stringFromJob)
    {
        XppClass myXppClass = new XppClass();
        // Subscribe two event handler methods to the delegate.
        myXppClass.myDelegate += eventHandler(myXppClass.myEventSubscriberMethod2);
        myXppClass.myDelegate += eventHandler(XppClass::myEventSubscriberMethod3);
        // Raise the event by calling the delegate one time,
        // which calls all the subscribed event handler methods.
        myXppClass.myDelegate(_stringFromJob);
    }
}

הפלט ממשימת X++ הקודמת הוא כדלקמן:

X++, hello from static event handler 
3: The information from the X++ job. X++, hello from instance event handler 
2: The information from the X++ job.

דוגמה ל- C#‎

מקטע זה מכיל דוגמת קוד C# עבור תבנית עיצוב האירוע של דוגמת X++ הקודמת.

// C#‎
using System;
// Define the delegate type named MyDelegate.
public delegate void MyDelegate(string _information);
public class CsClass
{
    protected event MyDelegate MyEvent;
    static public void Main()
    {
        CsClass myCsClass = new CsClass();
        // Subscribe two event handler methods to the delegate.
        myCsClass.MyEvent += new MyDelegate(myCsClass.MyEventSubscriberMethod2);
        myCsClass.MyEvent += new MyDelegate(CsClass.MyEventSubscriberMethod3);
        // Raise the event by calling the event one time, which
        // then calls all the subscribed event handler methods.
        myCsClass.MyEvent("The information from the C# Main.");
    }
    public void MyEventSubscriberMethod2(string _information)
    {
        Console.WriteLine("C#, hello from instance event handler 2: " + _information);
    }
    static public void MyEventSubscriberMethod3(string _information)
    {
        Console.WriteLine("C#, hello from static event handler 3: " + _information);
    }
}

הפלט מהמדגם הקודם של C# הוא כדלקמן:

CsClass.exe C#, hello from instance event handler 
2: The information from the C\# Main. C\#, hello from static event handler 
3: The information from the C\# Main.

אירועים ו- AOT

קיימות מערכות אירועים אחרות החלות רק על פריטים ב- AOT. לקבלת מידע נוסף, ראה צמתי המטפל באירועים ב- AOT.

השוואה: הוראה של קדם-compiler

X++ ו- C# משתפים מילות מפתח מסוימות עבור תחביר ההוראה של קדם-ההפצה, אך המשמעויות אינן זהות תמיד.

הדמיון

המהדרים של X++ ו- C# מזהים רבים מאותם מילות מפתח. ברוב המקרים, משמעות מילות המפתח זהה עבור שני מהדרי השפות.

ההבדלים

הבדל מהותי בין ההוראה של הקדם-קומימיילר ב- X++ לעומת C# #define המפתח ששניהם מכירים מראש של השפה. בניגוד ל- C#, ב- X++ #define דורשת נקודה בתחביר שלה. ב- X++, ניתן להשתמש בסוגריים כדי לתת לסימן המוגדר ערך. הבדלים אלה מוצגים בדוגמאות הבאות:

  • ב- X++: #define. שנת ראש השנה(2003)
  • In C#: #define InitialYear

הבדל משני הוא ש- C# יכול לכלול רווחים ותוי טאב בין התו # לבין מילת המפתח של הההוראה, כגון # define Testing.

מילות מפתח זהות

הטבלה הבאה מפרטת הוראה של קדם-compiler שדומים ב- X++ וב- C#‎.

מילת מפתח X++ C#‎ הערות
#define ב- X++, ניתן להגדיר שם משתנה של compiler מראש, וערך ניתן להינתן למשתנה זה. ב- C#, ניתן להגדיר שם משתנה של קומדר מראש, אך לא ניתן להינתן ערך למשתנה זה. כמו כן, #define ב- C# חייב להופיע בחלק העליון של הקובץ, ולא יכול להופיע לאחר קוד כלשהו, כגון משפט שימוש או הצהרת מחלקה. המהדר של C# יכול /define להזין פרמטר שורת פקודה של כדי להגדיר שם משתנה של קומפילר מראש מבלי להגדיר את המשתנה בכל קובץ קוד C#. המהדר של X++ אינו כולל חלק המקביל ל- /define.
#if ב- X++, #if לקבוע אם קיים משתנה של קומפליקט מראש ואם למשתנה יש ערך נתון. ב- C#, #if יכול לקבוע רק אם קיים משתנה של קדם-הפצה. אין לו אפשרות לבדוק אם קיים ערך מאחר שלא ניתן להקצות ערך.
#endif ב- X++, #endif מסמן את הסוף של #if בלוק. היא גם מסתיימת #ifnot בלוק. ב- C#, #endif מסמן את סוף בלוק #if, בין אם הבלוק כולל #else.

מילות מפתח שונות עם אותה תוצאת עיבוד

הטבלה הבאה מפרטת הוראה של קומבילטר בשם שונה ב- X++ וב- C#, אך הן מעניקות את אותן תוצאות בעת עיבודן.

X++ C#‎ הערות
#ifnot #if #else אין הוראה חדשה ב#else X++, אך ה- #ifnot מספק פונקציונליות דומה. ב- X++, #ifnot לקבוע אם משתנה קדם-הפצה קיים ואם למשתנה אין ערך נתון ספציפי. ב- C#, #if לקבוע אם משתנה קדם-הפצה קיים כאשר '!' סימן קידומת לשם המשתנה.
//BP Deviation documented #pragma אזהרה ערכי X++ ו- C# אלה אינם שווי ערך, אך קיימת דמיון חלקי. שתי הודעות האזהרה של המהדר מוסתרות.
#macrolib . קובץ HPP ב- C++‎ קיימת דמיון חלקי בין ההפנה של X++ #macrolib ל- . קובץ HPP ב- C++. שניהם יכולים להכיל מספר #define משפטי.

הוראה בלעדית של קדם-compiler ל- X++

הטבלה הבאה מפרטת הוראה של קדם-compiler של X++ שאין פריטים המקבילים ישירות ב- C#‎.

X++ הערות
#linenumber ההורה #linenumber הראשית היא להשגת מספר השורה, כך שניתן יהיה להוסיף פלט ל- Infolog.
ההצהרת C# #line שונה מאחר שהיא מיועדת להגדרת מספר השורה.
#defdec #definc
#globaldefine ב- X++, יש הבדל קטן בין #globaldefine לבין #define. ההבדל הוא ש- #globaldefine מחליף אף פעם ערך נוכחי שאינו Null שהוקצה למשתנה קדם-#define.
ל- C# אין דבר דומה להבדל זה, מכיוון ש- C#, לא ניתן לקבל שם משתנה של קומפליקציה מוקדמת.
#localmacro #macro ב- X++, #localmacro מאפשר לך להקצות ערך מרובה שורות למשתנה קדם-compiler. #macro זו מילה נרדפת, אך #localmacro היא מילה נרדפת.
ב- C#, #define ההקצאה כוללת חלק מפונקציונליות זו, אך אין לה אפשרות להקצות ערך למשתנה קומימיילר.
#globalmacro ב- X++, #globalmacro דומה כמעט לאותה שפה #localmacro.

השוואה: תכנות מונחה אובייקטים

עקרונות התיכנות מונחה האובייקטים (OOP) של X++ שונים מ- C#‎.

השוואות מושגיות

הטבלה הבאה משווה את היישום של עקרונות OOP בין X++ ל- C#‎.

תכונה X++ C#‎ הערות
ליהוק שפת X++ כוללת את מילות המפתח הן , וכן, המשמשות להפיכת שידורי ההלמטה בטוחים ומפורשים. עצה: X++ אינו דורש שימוש במילת המפתח בעת שידור מטה של משתנה מחלקת בסיס למשתנה מחלקה נגזר. עם זאת, מומלץ להשתמש במילת המפתח עבור כל משפטי שידור למטה . ניתן לשדר אובייקט למעלה או למטה בנתיב ההעברה בירושה. שידורי Downcast דורשים את מילת המפתח . לקבלת מידע נוסף אודות מילות המפתח של X++ הוא וכן, ראה אופרטורים של ביטויים: Is ו- As for Inheritance.
פונקציות מקומיות פעולת שירות יכולה להכיל גוף הצהרה וקוד עבור אפס או יותר פונקציות מקומיות. רק שיטה זו יכולה לכלול שיחות לפונקציה המקומית. C# 3.0 תומך בביטויים של lambda, בעלי דמיון לפונקציות אנונימיות ולפונקציות מקומיות. ביטויי Lambda משמשים לעתים קרובות עם נציגים.
עומס יתר של פעולת שירות עומס יתר של פעולת שירות אינו נתמך. שם פעולת שירות יכול להתרחש פעם אחת בלבד בכל מחלקה. עומס יתר של פעולת השירות נתמך. שם פעולת שירות יכול להתרחש מספר פעמים בכיתה אחת, עם חתימות פרמטרים שונות בכל מקרה. X++ תומך בפרמטרים אופציונליים בשיטות. פרמטרים אופציונליים יכולים למחוק באופן חלקי עומס יתר של פעולת שירות. לקבלת מידע נוסף, עיין בשורה לקבלת פרמטרים אופציונליים בטבלה זו.
פעולת שירות עוקף פעולת שירות עקיפה נתמכת. מחלקה נגזרת יכולה לכלול פעולת שירות בשם זהה למחלקה הבסיסית, כל עוד חתימת הפרמטר זהה בשני המקרים. החריג היחיד הוא כי פעולת השירות עקיפה יכולה להוסיף ערך ברירת מחדל לפרמטר. פעולת שירות עקיפה נתמכת. יש להחיל את מילת המפתח הווירטואלית על פעולת שירות כדי שניתן יהיה לעקוף את השיטה ברמה נגזרת. הרעיון של עקיפת פעולת שירות כולל את שם פעולת השירות, חתימת הפרמטר שלה וסוג ההחזרה שלה. הרעיון של עקיפת שיטה אינו חל אם שיטת הבסיס ושיטה העקיפה שונות בכל אחד מהיבטים אלה.
פרמטרים אופציונליים לאחר הצהרה על פרמטר יכולה להיות הקצאת ערך המהווה ברירת מחדל. המתקשר של פעולת השירות יכול להעביר ערך עבור פרמטר זה, או להתעלם מהפרמטר כדי לקבל את ערך ברירת המחדל. תכונה זו מחקה עומס יתר של פעולות שירות מאחר ששיחות לאותו שם שיטה יכולות להעביר מספרים שונים של פרמטרים. כל פרמטר בעל ערך ברירת מחדל חייב לעקוב אחר הפרמטר האחרון שאין לו ערך ברירת מחדל. פרמטרים אופציונליים נתמכים על-ידי מילת המפתח params . גם ללא מילת המפתח params , מנקודת הכניסה של המתקשר, עומס פעולת השירות יכול לספק פונקציונליות דומה חלקית. לקבלת מידע נוסף, ראה פרמטרים, הגדרת טווח והשימוש בפרמטרים אופציונליים.
ירושה בודדת באפשרותך להפיק את שיעור ה- X++ שלך ממחלקה אחרת של X++ באמצעות מילת המפתח המורחבת בצומת classDeclaration של הכיתה שלך, ב- AOT. אף כיתה לא נגזרת במפורש ישירות ממחלקה אחרת. אם ברצונך שהכיתה שלך תגזר ישירות מהכיתה Object , עליך להשתמש במילת המפתח המורחבת . באפשרותך לציין מחלקה אחת בלבד במילת המפתח המורחבת .

שים לב: בעת שינוי מחלקת בסיס של X++ שמגזר הכיתות האחרות, עליך להדר מחדש את מחלקת הבסיס באמצעות ההידור קדימה. אפשרות זו מבטיחה גם הידור מחדש של המחלקות הנגזרות. כדי להבטיח שהמחלקות הנגזרות עברו הידור מחדש גם כן, לחץ באמצעות לחצן העכבר הימני על צומת מחלקת הבסיס ולאחר מכן לחץ על Add-Ins > בצע הידור קדימה. החלופה ללחיצה על > הידור גירסת Build (או הקשה על מקש F7) אינה מספיקה לעתים לשינוי מחלקת בסיס.

מחלקה יכולה ליישם אפס בממשקים רבים.

טבלת X++ יורשת במפורש מהטבלה Common ומהמחלקה xRecord .
C# משתמש במילת המפתח המורחבת כדי להיגזר ממחלקה אחרת. כל מחלקות .NET Framework נגזרות באופן משתמע מהכיתה System.Object , אלא אם כן הן נגזרות באופן מפורש ממחלקה אחרת.

השוואות של מילות מפתח

הטבלה הבאה מפרטת את מילות המפתח הקשורות ל- OOP ב- X++ וב- C#‎.

מילת מפתח X++ C#‎ הערות
מופשט זה לא משנה .
מחלקה הפונקציה מתעלמת מהצירוףציבורי ופרטי בהצהרות כיתה. אין מושג של קיבוץ מרחב שמות של כיתות. אין נקודות (.) בשמות מחלקה כלשהם. ניתן להשתמש בצירוף מידעציבורי ופרטי לשינוי הצהרות מחלקה. ל- C# יש גם את מילת המפתח הפנימית, המתייחסת לאופן הקיבוץ של מחלקות בקובצי הרכבה. אין מושג של כיתה מוגנת , רק חברים מוגנים של כיתה.
מרחיב הצהרה על מחלקה יכולה לקבל בירושה ממחלקה אחרת באמצעות מילת המפתח המורחבת . נקודתיים (:) כאשר מילות המפתח מתרחבותומיושמות ב- X++.
הסופי לא ניתן לעקוף שיטה סופית בכיתה נגזרת. לא ניתן להרחיב כיתה סופית. מילת המפתח החותמת בכיתה פירושה אותה משמעות סופית בכיתה של X++ .
מיישם הצהרה על מחלקה יכולה ליישם ממשק באמצעות מילת המפתח המיישמת .
ממשק ממשק יכול לציין שיטות שיש ליישם על המחלקה. ממשק יכול לציין שיטות שיש ליישם על המחלקה.
חדש מילת המפתח החדשה משמשת להקצאת מופע חדש של מחלקה. לאחר מכן מתבצעת קריאה אוטומטית אל בנאי. לכל מחלקה יש בנאי אחד בדיוק, והבונים נקראים new. באפשרותך להחליט אילו פרמטרים יש להזין בנאי. מילת המפתח החדשה משמשת ליצירת מופע חדש של מחלקה. לאחר מכן מתבצעת קריאה אוטומטית אל בנאי. שיטות בנאי עצמן אינן נקראות newבשם , הן בעלות שם זהה לשם של הכיתה.

הערה: ניתן להשתמש במילת המפתח החדשה גם בשיטה, כדי לשנות את האופן שבו פעולת השירות עוקפת את אותה שיטה מחלקת הבסיס.

הן X++ והן C# מניחים בנאי ברירת מחדל עבור מחלקות שאין בנאי שנכתב במפורש בקוד שלהן.
Null זה לא משנה .
פרטיומוגן ניתן להשתמשבמילות המפתח הפרטיות והמוגנות כדי לשנות את ההצהרה של חבר כיתה. ניתן להשתמשבמילות המפתח הפרטיות והמוגנות כדי לשנות את ההצהרה של חבר כיתה.
ציבורית לשיטה שלא השתנה עם רמת גישה ציבורית, מוגנת או פרטית יש רמת גישה ציבורית המוגדרת כברירת מחדל. לשיטה שלא השתנה עם רמת גישהפרטית, ציבורית, מוגנת או פרטית, יש רמת גישה פרטית המהווה ברירת מחדל.
סטטי פעולת שירות יכולה להיות סטטית, אך שדה אינו יכול. הן שיטות והן שדות יכולים להיות סטטיים.
סופר מילת המפתח super משמשת בכיתה נגזרת כדי לגשת לאותה שיטה ברמה הבסיסית שלה. void method2()
{
// Call method2 method
// on the base class.
super();
}
מילת המפתח הבסיסית משמשת בכיתה נגזרת כדי לגשת לשיטות שונות מסוג הבסיס שלה.
void method2()
{
// Call methods on
// the base class.
base.method2();
base.method3();
}
ב- C#, קיים תחביר מיוחד לשימוש בבסיס כדי להתקשר אל בנאי הבסיס.
זה עבור שיחה משיטה אחת למופע אחר באותו אובייקט, נדרש מזהה עבור פעולת השירות שנקראה. מילת המפתח הזמינה כמזהה עבור האובייקט הנוכחי. עבור שיחה משיטה אחת למופע אחר באותו אובייקט, לא נדרש מזהה עבור פעולת השירות שנקראה. עם זאת , מילת המפתח זמינה כמזהה עבור האובייקט הנוכחי. בפועל, מילת המפתח יכולה להיות שימושית על-ידי הצגת מידע של IntelliSense.
finalize המחלקה Object מכילה את finalize השיטה. השיטה finalize אינה סופית, ובאפשרותך לעקוף אותה. נראה finalize שהשיטה דומה לשיטה ב System.Object.Finalize - C#, אך ב- X++ finalize לשיטה אין משמעות מיוחדת מכל סוג. אובייקט מוסר באופן אוטומטי מהזיכרון כאשר ההפניה האחרונה לאובייקט מפסיקה להפנות לאובייקט. לדוגמה, מצב זה עשוי להתרחש כאשר ההפניה האחרונה אינה בטווח או כאשר מוקצה לה אובייקט אחר שאליו יש להפנות. השיטות Finalize והן Dispose נפוצות בסוגים מסוימים של כיתות. אספן האשפה קורא לשיטות Finalize . Dispose והשיטות כאשר הוא הורס ואובייקט ב- C#, System.GC.Collect ניתן לבצע קריאה לפעולת השירות ב- .NET Framework כדי להפעיל את אספן האשפה. אין פונקציה דומה ב- X++ מכיוון ש- X++ משתמש אספן אשפה דטרמיניסטי.
main הכיתות שהופעלו מתוך תפריט כוללות את פעולת השירות main שלהן שהמערכת קראה לה. הכיתות שהופעלו ממסוף שורת פקודה נקראות על-ידי Main המערכת.

השוואה: כיתות

בעת שימוש ב- C# ב- .NET Framework, המחלקות מקובצות למרווחי שמות. כל מרחב שמות מתמקד באזור פונקציונלי כגון פעולות קובץ או השתקפות. עם זאת, בעת שימוש בכיתות ב- X++, אין קבץ גלוי כמו מרחב שמות.

השוואה: כיתות אודות השתקפות

ב- X++ המחלקה TreeNode מספקת גישה לעץ האובייקטים של היישום (AOT). TreeNode הכיתה היא מרכז פונקציונליות ההשתקפות ב- X++. ניתן TreeNode להשוות את המחלקה ואת השיטות שלה System.Reflection למרווח השמות ב- .NET Framework שבו משתמש C#‎.

הטבלה הבאה מפרטת כמה כיתות הזמינות עבורך בעת כתיבת קוד C#. אלה הן מחלקות .NET Framework עבור טבלה זו, כל מחלקות C# נמצאות מרחב השמות אלא System.Reflection אם צוין אחרת. כל שורה מציגה את הכיתה המתאימה, או את חבר הכיתה, הזמין עבורך בעת כתיבת קוד X++ שלך.

X++ C#‎ הערות
TreeNode System .Assembly הרכבה היא המחלקה הראשונה שבה יש להשתמש כאשר תוכנית C# חייבת לאסוף מידע השתקפות. שיטות סטטיות בכיתה X++ הן TreeNode נקודת ההתחלה עבור השתקפות ב- X++.
TreeNode System .Type פעולות שירות של מופע TreeNode ב- תואמות לשיטות המופע ב- System.Type.
TreeNode .AOTgetSource MethodInfo פעולת AOTgetSource השירות מחזירה כמה פיסות מידע יחד במחרוזת אחת. זה כולל את קוד המקור של X++ בפעולת השירות. לעומת זאת, MethodInfo יש חבר נפרד עבור כל פיסת מידע.
TreeNode .AOTfirstChild TreeNode .AOTnextSibling TreeNode .AOTiterator AOTiterator MethodInfo[] (מערך) ב- C#, GetMethods פעולת השירות on System.Type מחזירה מערך של אובייקטי MethodInfo. באפשרותך לעבור במערך בלולאה בטכניקה הנפוצה של הגדלה של בונה אינדקסים. לעומת זאת, מודל X++ הוא לנווט בפקד העץ של ה- AOT. השיטות TreeNode של AOTfirstChild ובצע AOTnextSibling את הניווט. לחלופין, המחלקה X++ AOTiterator מיועדת לנווט בפקד העץ של ה- AOT. צומת מחלקה הוא האב בכמה צמתי פעולת שירות. השלבים AOTiterator באמצעות צמתי צאצא, המחזירים כל אחד מהם כמופע TreeNode אחר. משאבים נוספים עבור פעולות TreeNode השירות ששמן הוא AOTparent ו- AOTprevious.
TreeNode .AOTgetProperty TreeNode .AOTgetProperties TreeNode .AOTname PropertyInfo ב- X++, AOTgetProperties פעולת השירות מחזירה מחרוזת ארוכה המכילה זוגות של שם-ערך עבור כל המאפיינים של TreeNode. פעולת AOTname השירות מחזירה מחרוזת המכילה רק את הערך עבור מאפיין השם.
TreeNode .AOTsave TreeNode .AOTinsert System .Reflection .Emit (מרחב שמות של מחלקות) פעולת AOTsave השירות מחילה שינויים מתוך TreeNode אובייקט בקוד X++ על ה- AOT, והשינויים נמשכים. לקבלת דוגמת קוד גדול, ראה פעולת השירות TreeNode.AOTsave.

השוואה: מחלקות אודות IO של קובץ

קיימות כמה מחלקות המבצעות פעולות קלט ופלט של קובץ (IO). ב- .NET Framework המשמש ב- C#, המחלקות המקבילות למחלקות אלה שוכנות מרחב System.IO השמות.

הטבלה הבאה מפרטת כמה מחלקות .NET Framework עבור C# מרחב System.IO השמות. כל שורה בטבלה מציגה את המחלקה או פעולת השירות של X++ המתאימה ביותר למחלקת .NET Framework

X++ C#‎ הערות
BinaryIo FileStream BinaryReader BinaryWriter כיתות X++ כגון אלה משתרעות BinaryIoIo מהכיתה המופשטת משמשות כזרם, והן משמשות גם כקורא וכותב עבור זרם זה. ב- C#, הזרם הוא כיתה נפרדת מהכיתה הכוללת שיטות קריאה וכתיבה ספציפיות יותר.
TextBuffer MemoryStream מחלקות אלה מכילות מאגר בזיכרון, ופעולות שירות מסוימות מתייחסות למאגר כאילו הוא קובץ בדיסק הקשיח.
WINAPI::createDirectory WINAPI::folderExists WINAPI::removeDirectory Directory DirectoryInfo Path X++ יכול להשתמש בשיטות סטטיות בכיתה WINAPI עבור פונקציות בסיסיות רבות של מערכת ההפעלה הכוללות ספריות.
WINAPI::getDriveType DriveInfo DriveType מחלקות ושיטות אלה משמשות להשגת מידע הקשור לכונן.
WINAPI::copyFile WINAPI::createFile WINAPI::d eleteFile WINAPI::fileExists File FileAttributes FileInfo X++ יכול להשתמש בשיטות סטטיות בכיתה WINAPI עבור פונקציות בסיסיות רבות של מערכת ההפעלה הכוללות קבצים.
CommaIo Comma7Io (אין מחלקה תואמת.) מחלקות X++ אלה יכולות ליצור קבצים ש- Microsoft Excel יכול לייבא. ב- X++ הפניה לספריית EPPlus זמינה לאינטראקציה נוספת עם Excel.
AsciiIo TextIo FileStream TextReader TextWriter כיתות אלה משתמשות בדפים שונים של קודים.
Io Stream StreamReader StreamWriter FileStream מחלקות אלה משמשות לעתים קרובות ככיתות בסיס שכיתות אחרות מרחיבות.
CodeAccessPermission FileIoPermission System.Security .CodeAccessPermission מרחב השמות כולל System.Security.Permissions את המחלקות הבאות:
  • CodeAccessSecurityAttribute
  • FileIOPermissionAttribute
  • FileIOPermission
  • FileIOPermissionAccess
המושגים והשיטות של assert, demandוחלים revertAssert על שתי השפות. עם זאת, deny פעולות השירות revertDeny הזמינות ב- C# אינן זמינות ב- X++.

X++, ANSI SQL Comparison: SQL Select

ב- X++, תחביר משפט בחירת ה- SQL שונה ממפרט מכון התקנים הלאומי האמריקאי (ANSI).

בחירת טבלה יחידה

הטבלה הבאה מפרטת הבדלים בין המשפטים שנבחרו של X++ SQL ו- ANSI SQL.

תכונה X++ SQL ANSI SQL הערות
שם טבלה במשפט from . משפט from מפרט מופע מאגר רשומות שהוצהר מטבלה, כגון מהטבלה CustTable . משפט from מפרט שם טבלה, ולא את שם המאגר. מאגר הרשומות כולל את כל פעולות השירות הקיימות בכיתה xRecordב- X++.
רצף תחביר של הסדר בפסוקיות where לעומת פסוקיות. המשפט order by חייב להופיע לפני משפט where . המשפט order by חייב להופיע לאחר משפט from אוjoin . על הפסוקית group by לפעול לפי אותם כללי מיקום תחביר שלהלן. המשפט order by חייב להופיע לאחר משפט where . משפט where חייב להופיע לאחר משפט from אוjoin . הן ב- X++ והן ב- ANSI SQL, משפטי from ו- join חייבים להופיע לפני משפטי order by ו - where .
תנאי שלילה. סימן הקריאה ('!') משמש עבור שלילה. לא נעשה שימוש במילת המפתח לצורך שלילה. X++ אינו תומך בתחביר !like. במקום זאת, עליך להחיל את ! אופרטור לפסוקית.
תווים כלליים עבור האופרטור Like . 0 לרבים – כוכבית ('*')
בדיוק 1 – סימן שאלה ('?')
0 לרבים – סימן אחוז ('%')
בדיוק 1 – קו תחתון ('_')
אופרטורים לוגיים במשפט where . וגם – &
Or – ||
ו- – וכן
לחלופין – או

דוגמת קוד

דוגמת הקוד הבאה ממחישה תכונות בטבלה הקודמת.

static void OByWhere452Job(Args _args)
{
    // Declare the table buffer variable.
    CustTable tCustTable;
    ;
    while
    SELECT * from tCustTable
        order by tCustTable.AccountNum desc
        where (!(tCustTable.Name like '*i*i*') &amp;&amp; tCustTable.Name like 'T?e *')
    {
        info(tCustTable.AccountNum + " , " + tCustTable.Name);
    }
}
/*** InfoLog output
Message (04:02:29 pm)
4010 , The Lamp Shop
4008 , The Warehouse
4001 , The Bulb
***/

מילות מפתח של X++ SQL

מילות המפתח הבאות של X++ SQL הן בין מילות המפתח אינן חלק מ- ANSI SQL:

  • crosscompany
  • פרטי בלבד100
  • תעתיקי כוח
  • forcenestedloop
  • בעלי מעלי כוח
  • מפענח כוח
  • validtimestate

פסוקית צירוף

הטבלה הבאה מפרטת הבדלים לגבי מילת המפתח צירוף של X++ SQL ו- ANSI SQL.

תכונה X++ SQL ANSI SQL הערות
רשימת עמודות. כל העמודות ברשימת העמודות חייבות להגיע מהטבלה המפורטת במשפט from , ולא מטבלה כלשהי במשפט צירוף . עמודות ברשימה אינן יכולות להיות מלאות לפי שם הטבלה שלהן. העמודות ברשימת העמודות יכולות להגיע מכל טבלה במשפטי fromאו join . הוא עוזר לאחרים לשמור את הקוד שלך כאשר אתה מעניק זכאות לעמודות ברשימה עם שם הטבלה שלהם. לקבלת מידע נוסף, ראה בחירת משפטים בשדות.
תחביר משפט צירוף. פסוקית הצירוף פועלת בהתאם לפסוקית where. פסוקית הצירוף מופיעה אחרי טבלה בפסוקית from. בדוגמה של קוד X++, קריטריוני הצירוף הם שוויון SalesPoolId בין ערכים.
מילת מפתח פנימית. מצב הצירוף המוגדר כברירת מחדל הוא צירוף פנימי. אין מילת מפתח פנימית . מצב הצירוף המוגדר כברירת מחדל הוא צירוף פנימי. מילת המפתח הפנימית זמינה כדי להפוך את הקוד למפורש. מילת המפתח היוצאת קיימת הן ב- X++ SQL והן ב- ANSI SQL.
מילות מפתחשמאלה וימניות . מילות המפתחשמאלה וימני אינן זמינות. כל הצירוף נותר. מילות המפתחשמאלה וימני זמינות לשינוי מילת המפתח של הצירוף . אין הערות.
אופרטור שוויון. אופרטור סימן השוויון כפול ('==') משמש לבדיקת השוויון של שני ערכים. אופרטור סימן שוויון יחיד ('=') משמש לבדיקת השוויון בין שני ערכים. אין הערות.

דוגמת קוד

דוגמת הקוד הבאה מדגימה את תחביר הצירוף ב- X++ SQL.

static void OByWhere453Job(Args _args)
{
    // Declare table buffer variables.
    CustTable tCustTable;
    SalesPool tSalesPool;
    ;
    while
    SELECT
            // Not allowed to qualify by table buffer.
            // These fields must be from the table
            // in the from clause.
            AccountNum,
            Name
        from tCustTable
            order by tCustTable.AccountNum desc
            where (tCustTable.Name like 'The *')
        join tSalesPool
            where tCustTable.SalesPoolId == tSalesPool.SalesPoolId
    {
        info(tCustTable.AccountNum + " , " + tCustTable.Name);
    }
}

שדות צבירה

הטבלה הבאה מפרטת כמה הבדלים באופן ההפניה לשדות צבירה ברשימת העמודות שנבחרו בין X++ SQL ל- ANSI SQL. שדות צבירה הם שדות הנגזרים מפונקציות כגון sum או avg.

תכונה X++ SQL ANSI SQL הערות
כינוי שם שדה צבירה. ערך הצבירה נמצא בשדה שהיה נצבר. באפשרותך להשתמש במילת המפתח כדי לתייג שדה צבירה עם כינוי שם. ניתן להפנות אל הכינוי בקוד הבא. לקבלת מידע נוסף, ראה פונקציות צבירה: הבדלים בין X++ ל- SQL

דוגמת קוד

בדוגמה הבאה של הקוד, השיחה אל שיטת המידע ממחישה את הדרך להפניה לשדות צבירה (ראה tPurchLine.QtyOrdered).

static void Null673Job(Args _args)
{
    PurchLine tPurchLine;
    ;
    while
    select
        // This aggregate field cannot be assigned an alias name.
        sum(QtyOrdered)
        from tPurchLine
    {
        info(
            // QtyOrdered is used to reference the sum.
            "QtyOrdered:  " + num2str(tPurchLine.QtyOrdered, 
            3,  // Minimum number of output characters.
            2,  // Required number of decimal places in the output.
            1,  // '.'  Separator to mark the start of the decimal places.
            2   // ','  The thousands separator.
            ));
    }
    info("End.");
}
/***
Message (12:23:08 pm)
QtyOrdered:  261,550.00
End.
***/

הבדלים אחרים

הטבלה הבאה מפרטת הבדלים אחרים במשפט select בין X++ SQL ל- ANSI SQL.

תכונה X++ SQL ANSI SQL הערות
מילת המפתח שיש . אין מילת מפתח. מילת המפתח הכוללת מאפשרת לך לציין קריטריוני סינון עבור שורות שנוצרות על-ידי הקבוצה לפי משפט. אין הערות.
תוצאות Null. בתוך זמן מה משפט בחירה, אם משפט where מסנן את כל השורות, לא מוחזרת שורת ספירה מיוחדת כדי לדווח על כך. בבחירה , אם משפט where מסנן את כל השורות, מוחזרת שורת ספירה מיוחדת. ערך הספירה הוא 0. אין הערות.
סמנים לניווט בשורות שהוחזרו. משפט בחירה בזמן מספק פונקציונליות של הסמן. החלופה היא שימוש במילת המפתח הבאה. באפשרותך להצהיר על סמן לצורך מעבר בלולאה בין השורות המוחזרות ממש משפט בחירה.
מפסוקית . מילת המפתח From היא אופציונלית כאשר לא מופיעות עמודות והפניה לטבלה אחת בלבד. שתי אפשרויות התחביר הבאות הן שווי ערך:
select \* from tCustTable;
select tCustTable;
משפט בחירה אינו יכול לקרוא מטבלה אלא אם נעשה שימוש במשפט from . ב- X++ SQL, משפט הבחירה הפשוט ממלא את משתנה המאגר של הטבלה בשורה הראשונה שהוחזרה. זה מוצג על-ידי קטע הקוד הבא:
select \* from tCustTable;
info(tCustTable.Name);