共用方式為


X++ 與 C# 的比較

備註

社區興趣小組現在已從 Yammer 轉移到 Microsoft Viva Engage。 若要加入 Viva Engage 社群並參與最新的討論,請填寫 [ 要求存取財務和營運 Viva Engage 社群 表單 」 ,並選擇您要加入的社群。

本文比較 X++ 和 C# 語法和程式設計。

X++、C# 比較:Hello World

本節將最簡單的 X++ 程式與 C# 中的對應程式進行比較。

X++ 與 C# 的比較

以下各節描述 X++ 和 C# 之間的一些基本相似之處和差異。

相似之處

下列 X++ 功能與 C# 相同:

  • 單行 (//) 和多行 (/* */) 註解。
  • == (等於) 運算子,用於判斷兩個值是否相等。
  • != (不等於) 運算子,用於判斷兩個值是否不相等。
  • + (加號) 運算子來串連。

Differences

下表列出 C# 中不同的 X++ 功能。

特徵 / 功能 X++的 C# 評論
ifelse 條件語句 陳述 if 式接受任何類型的運算式,可自動轉換為布林值。 常見的範例包括 int 0 表示 false,或 null 表示 false 的物件。 if 陳述式需要布林運算式。 關於大括號和括號的語法結構在 X++ 和 C# 之間完全相同。
常值字串 可以使用下列其中一種方法來定隔常值字串:
  • 一對雙引號 (“) 字元。
  • 一對單引號 (') 字元。
常值字串必須以一對雙引號 (“) 字元分隔。 對於 X++,雙引號字元通常用於分隔字串。 不過,當您的字串必須包含雙引號字元時,使用單引號字元分隔字串很方便。
type X++ 中沒有 char 或 字元類型。 您可以宣告 str 長度為 1,但它仍然是一個字串:
str 1 myString = "a";
C# 中有一個 char 。 您無法將 a char 作為參數傳遞給輸入 string 參數的方法,儘管您可以先明確地將 轉換為 charstring 如需 X++ 資料類型的詳細資訊,請參閱 基本資料類型。
訊息輸出 X++ 會在 Infolog 視窗中傳送訊息給使用者。 常見的方法包括:
  • 列印聲明:
  • 靜態方法 Global
    • 全域::info
    • 全域::警告
    • 全域::錯誤
對於指令行程式,可以將訊息傳遞至主控台。 常見的方法包括:
  • Console.Out.WriteLine
  • Console.Error.WriteLine

X++ 和 C# 範例

本節包含兩個簡單的程式碼範例。 一個範例是用 X++ 編寫的,另一個是用 C# 編寫的。 兩個樣本都達到相同的結果。 示範下列 X++ 功能:

  • // 單行註解
  • /\* \*/ 多行註解
  • if 陳述
  • == 運算子
  • != 運算子
  • + 連接字串的運算子
  • Global::info 用於訊息輸出,有和沒有 Global:: 前置詞
  • Global::error 用於訊息輸出
  • 使用單引號和雙引號字元 (' 和 “) 作為字串分隔符號。

備註

最佳作法是對可能向使用者顯示的任何字串使用雙引號。

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. 你好世界」、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 語句 for 迴圈。
  • break 語句來退出迴圈。
  • continue 陳述式以跳至迴圈頂端。
  • <=(小於或等於)比較運算子。

Differences

下表列出 C# 中不同的 X++ 功能。

Features X++的 C# 評論
聲明。for for 陳述式可用於迴圈。 C# for 語句與 X++ 中的陳述式略 for 有不同。 在 C# 中,您可以在語句中 for 宣告計數整數。 但在 X++ 中,計數器必須在語句之外 for 宣告。
++ 增量運算子。 ++ 增量運算子可在 X++ 中使用。 但是用++裝飾的 int 變數只能作為語句使用,不能作為表達式使用。 例如,下列 X++ 程式碼行不會編譯:
int age=42;
print age++;
不過,下列 X++ 程式碼行會編譯:
int age=42;
age++; print age;
C# ++ 運算子比 X++ 更靈活。 下列程式碼行在兩種語言中相同:
  • ++ 我的整數;
  • myInteger++;
但下列程式碼行彼此的效果不同,且僅在 C# 中有效:
  • yourInt = ++myInt;
  • 你的 Int = 我的 Int++;
模運算子。 在 X++ 中,模運算子是 mod。 在 C# 中,模運算子 %。 模運算子的符號不同,但它們在兩種語言中的行為是相同的。
暫時暫停已開始的主機程式。 聲明。pause 在 C# 中,命令列程式可以透過以下程式碼行暫停:
Console.In.Read();
在 X++ 中,您可以按一下強制回應對話方塊上的 [確定] 按鈕,以繼續。 在 C# 中,您可以按鍵盤上的任何鍵盤繼續。
顯示訊息。 在 X++ 中,陳述 print 式會在 [列印] 視窗中顯示訊息。 在 C# 中,訊息可以透過下列程式碼行顯示在主控台上:
Console.WriteLine();
只有在您測試時才會使用 X++ print 函式。 使用 print 的 X++ 程式幾乎總是在程式碼後面的某個位置使用 pause 語句。 對於生產 X++ 程式碼,請使用 Global::info 方法,而不是 print。 該 strfmt 函數通常與 info一起使用。 沒有理由在之後pause使用 info
發出聲音。 蜂鳴功能會發出您可以聽到的聲音。 在 C# 中,您可以聽到的音效是由下列程式碼行發出:
Console.Beep();
這些陳述都產生了簡短的語氣。

迴圈的 X++ 程式碼範例會使用函 print 式來顯示結果。 在 X++ 中,您可以使用該 print 語句可以顯示任何原始資料類型,而無需先呼叫將其轉換為字串的函數。 這在快速測試情況下很 print 有用。 一般而言,Global::info 方法的使用頻率 print高於 。 該 info 方法只能顯示字串。 因此,strfmt函數經常與 info一起使用。 的 print 限制是您無法將 [列印] 視窗的內容複製到剪貼簿 (例如 Ctrl+C)。 Global::info 寫入 Infolog 窗口,該窗口支持複製到剪貼板。

範例 1:while 迴圈

while 關鍵字支援 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++ 列印] 視窗中的輸出如下:

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:for 迴圈

for 關鍵字支援 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++ 列印] 視窗中的輸出如下:

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# 比較:切換

在 X++ 和 C# 中, switch 語句都涉及關鍵字 casebreakdefault。 下表列出 X++ 和 C# 之間 switch 陳述式的差異。

特徵 / 功能 X++的 C# 評論
break; 在每個案例區塊的結尾 在 X++ 中,當任何 case 區塊符合 switch 子句上的運算式值時,會執行所有其他 case預設 區塊,直到達到陳述式為止 break; 。 X++ switch 陳述式中不需要任何break;陳述式,但 break;陳述式在幾乎所有實際情況下都很重要。 在 C# 中,break;default 區塊中的陳述式之後一律需要陳述式。 如果 case 子句本身與下一個 case 子句之間沒有陳述式, break; 則兩個 case 子句之間不需要陳述式。 我們建議不要在任何 case break;之後省略該語句,因為它可能會混淆下一個編輯程式碼的程式設計師。
break;預設 區塊的結尾 在 X++ 中,在break;區塊結尾新增陳述式不會有效果。 在 C# 中,編譯器需要break;預設區塊結尾的陳述式。 如需詳細資訊,請參閱 Switch 陳述式。
只有 觀察值 區塊上的常數值 在 X++ 中,您可以在 case 區塊上指定常值或變數。 例如,您可以寫case myInteger:。 在 C# 中,您必須在每個 case 區塊上指定一個常值,而且不允許任何變數。 沒有評論。
一個 觀察值 區塊上的多個值 在 X++ 中,您可以在每個 case 區塊上指定多個值。 這些值必須以逗號分隔。 例如,您可以寫 case 4,5,myInteger:. 在 C# 中,您必須在每個 案例 區塊上只指定一個值。 在 X++ 中,最好在一個 case 區塊上寫入多個值,而不是省略 break; 一或多個 case 區塊結尾的語句。

switch 的程式碼範例

下列各節顯示 X++ 和 C# 中的類似 switch 陳述式。

X++ 開關範例

X++ 參數範例顯示下列內容:

  • case iTemp:case (93-90): 顯示 大小寫 運算式不限於常數,就像 C# 中一樣。
  • //break; 以顯示 break; X++ 中不需要語句,儘管它們幾乎總是可取的。
  • case 2, (93-90), 5: 以顯示 X++ 中的一個 case 子句上可以列出多個運算式。
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:有一個註釋解釋了 case 子句只能給出常數表達式。
  • 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 符號 (@) 會使反斜線的逸出效果無效。
  • 加號 (+) 是字串串連運算子。

Differences

下表列出 C# 中不同的 X++ 功能。

特徵 / 功能 X++的 C# 評論
== 比較運算子 不敏感:運算子 == 對字串大小寫的差異不敏感。 在 C# 中,運算子 == 對字串大小寫的差異很敏感。 在 X++ 中,您可以使用 strCmp 函式在字串之間進行區分大小寫的比較。
字串分隔符號 在 X++ 中,您可以使用單引號 (') 或雙引號 (") 作為字串分隔符號。

便條: 通常最佳作法是針對可能顯示給使用者的字串使用雙引號。 不過,當雙引號是字串中的字元之一時,使用單引號分隔字串會很方便。

在 C# 中,您必須使用雙引號作為字串分隔符號。 這是指類型 System.String. 在 X++ 和 C# 中,您可以選擇在文字字串中內嵌分隔符,並使用 .
在 X++ 中,您也可以將單引號內嵌在以雙引號 (或相反) 分隔的字串中,而不需要使用逸出符號。
字元分隔符號 X++ 具有字串資料類型 (str),但沒有字元類型。 在 C# 中,您必須使用單引號作為字元分隔符號。 這是指類型 System.Char. 在 .NET Framework 中, System.String 長度 1 與字元的資料 System.Char 類型不同。

範例 1:== 運算子的區分大小寫

== != 運算子在 X++ 中不區分大小寫,但在 C# 中區分大小寫,如下列範例所示。

X++的 C# 評論
"HELLO" == "hello"
在 X++ 中為 True。
"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++ 中的字串。 轉義字元 (\) 可用來在字串中內嵌定界字元。 下表說明了這些。

X++的 C# 評論
myString1 = "They said \"yes\".";
結果:
They said "yes".
(與 X++ 相同。 逸出字元可讓您在字串內嵌入字串分隔符號。
myString2 = 'They said "yes".';
結果:
They said "yes".
C# 語法不允許使用單引號來分隔字串。 對於使用者可能看到的字串,最佳做法是使用逸出字元,而不是單引號,如範例所示。
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 中的數據類型。 長度限制為 1 的 X++ 字串仍然是字串,而不是字元資料類型。

範例 4:單一轉義字元

下表顯示說明輸入或輸出中單一逸出字元的範例。

X++的 C# 評論
myString1 = "Red\ shoe";
結果:
Red shoe
C# 中的常值字串不能包含跳出的兩個字元序列,後面接著空格,例如 “\ ”。 發生編譯器錯誤。 當 X++ 編譯器遇到 “\ ” 的兩個字元序列時,它會捨棄單一轉義字元。
myString2 = "Red\\ shoe";
結果:
Red\ shoe
(與 X++ 相同。 在一對轉義字元中,第一個否定了第二個字元的特殊意義。

比較:陣列語法

X++ 與 C# 中陣列的功能和語法有相似之處和差異。

相似之處

總體而言,X++ 和 C# 中數組的語法和處理方式非常相似。 然而,存在許多差異。

Differences

下表列出 [] 語法中針對 X++ 和 C# 不同的陣列區域。

類別 X++的 C# 評論
聲明 陣列會以方括號附加至變數名稱來宣告。 陣列會以方括弧附加至資料類型來宣告。 int myInts[]; // X++

便條: X++ 陣列不能是方法中的參數。

int[] myInts; // C#

聲明 陣列語法僅支援基本資料類型,例如 intstr。 語法不支援類別或資料表。 陣列語法支援原始資料類型和類別。 在 X++ 中,您可以將 Array 用於 Array 物件陣列。
聲明 X++ 僅限於單維數陣列 (myStrings[8])。 C# 新增了對多維度陣列 (myStrings[8,3]) 和鋸齒狀陣列 (myStrings[8][3]) 的支援。 在 X++ 中,您不能擁有陣列的陣列。 不過,有進階語法可限制大型陣列可以耗用的作用中記憶體量,這看起來像 C# 中的多維語法:int intArray[1024,16];。 如需詳細資訊,請參閱最佳實務效能最佳化:將陣列交換至磁碟。
聲明 在 X++ 中,數組是一種特殊的構造,但它不是物件。 在 C# 中,所有陣列都是物件,無論語法變化如何。 X++ 確實有一個 Array 類,但其基礎機制與使用 [] 語法建立的陣列不同。 在 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]));
    }
}
輸出

資訊日誌的輸出如下:

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 集合類別。 C# 中使用的 .NET Framework 有一個名為 的類似類別 System.Collections.Generic.List

比較清單類別的使用方式

下表比較 X++ List 類別上的方法與 .NET Framework 和 C# 上的方法 System.Collections.Generic.List

特徵 / 功能 X++的 C# 評論
收款聲明 List myList; List<string> myList; X++ 宣告不包含要儲存的元素類型。
迭代器的宣告 ListIterator iter
ListEnumerator enumer;
IEnumerator<字串> iter; 在 X++ ListIterator 中,物件具有可以 insertdeleteList項目的方法。 X++ ListEnumerator 無法修改 List. 在 X++ ListEnumerator 中,物件一律會建立在與 .List 對於 來說,情況並非總是如此 ListIterator
取得疊代器 new ListIterator (myList)
myList.getEnumerator()
myList.GetEnumerator() 在 X++ 和 C# 中,List 物件都有相關聯列舉值的 getter 方法。
建構函式 new List(Types::String) new List<string>() 有關要存儲在類中的 List 對象類型的信息在 X++ 和 C# 中提供給建構函數。
更新資料 列舉值 – 如果新增或移除 中 List 的任何專案,列舉值就會變成無效。
迭代器 – 迭代器具有從 中 List插入和刪除項目的方法。 迭代器仍然有效。
列舉值 – 如果新增或移除 中 List 的任何專案,列舉值就會變成無效。 列舉式會在 X++ 和 C# 中從 新增或刪除 List專案之後變成無效。
更新資料 在 X++ 中,類別 List 具有在清單開頭或結尾新增專案的方法。 在 C# 中,類別 List 具有在清單中任何位置新增成員的方法。 它還具有從任何位置刪除項目的方法。 在 X++ 中,專案可以由迭代器從 中 List 移除。

範例 1:清單的宣告

下列程式碼範例是宣告 List 集合的 X++ 和 C# 中。

// 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:C 中的 foreach#

在 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集合會保留值對,索引鍵值加上資料值。 這類似於名為 System.Collections.Generic.Dictionary的 .NET Framework 類。

相似之處

下列清單描述 X++ 和 C# 之間儲存索引鍵值組的集合的相似之處:

  • 兩者都可以防止重複的金鑰。
  • 兩者都使用列舉值 (或疊代器) 來迴圈專案。
  • 這兩個索引鍵值集合物件都是使用儲存為索引鍵和值的類型名稱來建構。
  • 兩者都可以儲存類別對象,並且不限於儲存 int 等原語。

Differences

下表描述 X++ 和 C# 之間關於儲存索引鍵值組的集合類別的差異:

特徵 / 功能 X++的 C# 評論
重複的金鑰 在 X++ 中,類別會 Map 隱含地將對其 insert 方法的呼叫視為僅更新與索引鍵相關聯的值的作業,以防止重複索引鍵。 在 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:逐一查看 Key-Value 集合

列舉式可用來迴圈 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# 之間的異常相關行為時,有一些相似之處,但也有很多不同之處。 trycatchthrow 關鍵字在 X++ 和 C# 中的行為相同。 但擲回和攔截的例外類型對於兩種語言不同。

相似之處

X++ 和 C# 在例外功能方面的相似之處包括以下範例:

  • 兩種語言都有相同的 try 關鍵字。
  • 兩者都有相同的 catch 關鍵字。
  • 兩者都會啟用未指定任何特定例外狀況的 catch 陳述式。 這類 catch 陳述式會攔截到達它的所有例外狀況。
  • 兩者都有相同的 throw 關鍵字。

Differences

下表說明 X++ 與 C# 之間的例外狀況相關差異。

特徵 / 功能 X++的 C# 評論
重試 跳至相關聯的 try 區塊中的第一個指令。 如需詳細資訊,請參閱使用 try 和 catch 關鍵字進行例外狀況處理。 retry 關鍵字的功能可以在 C# 程式碼中模擬,但沒有對應的關鍵字。 只有 X++ 有 重試 關鍵字。 C# 沒有對應的。 如需詳細資訊,請參閱 X++、C# 比較:例外狀況後自動重試。
finally支持關鍵字跟隨 trycatch 關鍵字。 finally 關鍵字會標示 trycatch 區塊後面的程式碼區塊。 無論擲回或捕獲任何異常,finally 都會被執行。 語意與 C# 中的語意相同。
特定例外情況 在 X++ 中,例外狀況是列舉的 Exception 元素,例如 ErrorDeadlockCodeAccessSecurity。 任何例外狀況都不能包含另一個例外狀況。 在 C# 中,例外狀況是基底類別的 System.Exception 實例,或繼承自基底類別的任何類別。 例外狀況可以包含在擲回例外狀況的屬性中 InnerException 在 X++ 中,每個擲回的例外狀況都是 Exception 列舉的值。 如需詳細資訊,請參閱例外狀況列舉。
異常訊息 在 X++ 中,引發異常狀況時所建立的訊息僅在資訊日誌中可用,且訊息不會直接繫結至例外狀況。 在 C# 中,訊息是 Message 物件的 System.Exception 成員。 在 X++ 中,Global::error 方法是在資訊日誌中顯示異常訊息的機制。 如需詳細資訊,請參閱使用 try 和 catch 關鍵字進行例外狀況處理。
例外狀況 在 X++ 中,當您在尚未指派任何專案的物件變數上呼叫實例方法時,就會發生錯誤。 不過,此錯誤不會引發任何例外狀況。 因此,即使未分配的變量在塊中catch被誤用,也沒有塊try可以獲得控制權。 在下列程式碼範例中,程式碼 box4.toString(); 所造成的錯誤不會導致控制權轉移到任何 catch 區塊: DialogBox box4;try { box4.toString(); info("toString did not error, but expected an error."); } catch (Exception::Error) // 沒有例外狀況值會擷取此專案。 { info("Invalid use of box4 gave control to catch, unexpected."); } 在 C# 中,當未初始化的變數被視為物件參考時,會引發 a System.NullReferenceException 引發例外狀況的條件可能還有其他數個差異。
SQL 交易 在X++中,當 ttsBegin - ttsCommit 事務中發生SQL異常時,事務區塊內沒有任何 catch 語句可以處理異常。 在 C# 中,SQL 事務內的 catch 區塊可以捕獲異常。

範例

示範下列 X++ 功能:

  • try 關鍵字。
  • catch 關鍵字。
  • 發生 Exception::Error 例外狀況之後的行為。

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.

比較:例外狀況後自動重試

有時您可以在 catch 區塊中撰寫程式碼,以修正執行階段發生的例外狀況原因。 X++ 提供了一個只能在 catch 區塊內使用的重試關鍵字。 retry 關鍵字可讓程式在 catch 區塊中的程式碼更正問題之後跳回 try 區塊的開頭。 C# 沒有 重試 關鍵字。 不過,可以撰寫 C# 程式碼來提供對等的行為。

重試的程式碼範例

下列 X++ 範例程式會導致引發 Exception::Error。 當它第一次嘗試使用無效的索引值從陣列讀取 sStrings 元素時,就會發生這種情況。 攔截異常狀況時,會在 catch 區塊內的執行階段採取更正動作。 然後,retry 陳述式會跳回 try 區塊中的第一個陳述式。 第二次迭代可以正常工作,不會遇到任何例外。

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++ 程式所依賴的 retry 關鍵字的行為。 trycatch 區塊位於呼叫的方法中。 try 區塊中使用的變數會儲存在呼叫端方法中。 呼叫端方法會將變數傳遞為以 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# Differences
= 在 X++ 中,每當可能發生精確度損失時,此運算子都會造成隱含轉換,例如從 int64int 的賦值。但在 C# 中,賦值會導致編譯錯誤。
+=-= 唯一的差異是,在 C# 中,這些運算子也用於委派操作。
++ 和 -- 這些是兩種語言的遞增和遞減運算子。 以下行在兩種語言中是相同的:
++myInteger;
但在 X++ 中,這兩個運算子是 for 語句,而不是表達式。 因此,下列行會在 X++ 中產生編譯錯誤:
myStr = int2str(++myInteger);
myIntA = myIntBB++;

算術運算子

下表列出算術運算子。

X++ 和 C# Differences
* 作為乘法運算子,沒有區別。

便條: 星號也用於屬於 X++ 語言一部分的 SQL 陳述式中。 在這些 SQL 陳述式中,星號也可以是下列其中一項:

  • 萬用字元,指出應傳回所有資料行。
  • 字串中用於 like 子句的字元萬用字元。
/ 除法運算子在 X++ 和 C# 中是相同的。
MOD 對於模運算,唯一的區別是 C# 中使用了 % 符號。
+ 加法運算子在 X++ 和 C# 中是相同的。 加號也用於字串串連。 此運算子會新增數字並串連兩種語言的字串。
- 減法運算子在 X++ 和 C# 中是相同的。

位元運算子

下表比較 X++ 和 C# 之間的位元運算子。

X++ 和 C# Differences
<< 左移運算子在 X++ 和 C# 中是相同的。
>> 右移運算子在 X++ 和 C# 中是相同的。
~ 位元 NOT 運算子在 X++ 和 C# 中是相同的。
& 二進位 AND 運算子在 X++ 和 C# 中是相同的。
^ 二進位 XOR 運算子在 X++ 和 C# 中是相同的。

關聯式運算子

下列關聯式運算子在 X++ 和 C# 中是相同的:

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

比較:事件

X++ 和 C# 實作事件設計模式的方式有一些差異。 如需詳細資訊,請參閱事件術語和關鍵字。

X++ 和 C 之間的事件比較#

在 X++ 與 C# 中,委派用於事件的方式有差異。

概念 X++的 C# 評論
delegate 在 X++ 中,委派只能宣告為類別上的成員。 代理人不能是表格上的成員。 所有委派都是其類別的實例成員,而不是 靜態 成員。 任何存取修飾詞都不能用於委派宣告,因為所有委派都是 受保護 的成員。 因此,事件只能由委派所屬之相同類別內的程式碼引發。 不過,委派私人性質的一個例外是,其類別外部的程式碼可以使用 += 和 -= 運算子對委派進行操作。 在 C# 中,每個 委派 都是一個類型,就像每個 類別 都是一個類型一樣。 委派是獨立於任何類別宣告的。 如果沒有 event 關鍵字,您可以將委派作為方法上的參數類型,就像您可以將類別作為參數類型一樣。 您可以建構委派的實例,以傳入參數值。 在 X++ 中,每個類別都是一個類型,但沒有委託是類型。 您無法建構委派的實例。 任何委派都不能是方法的參數。 但您可以建立具有委派成員的類別,而且您可以將類別的實例作為參數值傳遞。 如需詳細資訊,請參閱 X++ 關鍵字。
事件 在 X++ 程式碼中,事件是下列其中一項:
  • 明確呼叫代理人。
  • 方法的開始或結束。
X++ 中沒有 事件 關鍵字。
在 C# 中, event 關鍵字用於將 委託 類型宣告為類別的成員。 event 關鍵字的效果是讓委派受到保護,但仍可供 += 和 -= 運算子存取。 您可以使用 += 運算子將事件處理常式方法訂閱 至事件委派在沒有 event 關鍵字的情況下也很有用,作為將函數指標作為參數傳遞至方法的技術。 在方法開始之前,以及方法結束之後發生的自動事件,只能使用 AOT 來訂閱。
+= 和 -= 運算子 在 X++ 中,您可以使用 += 運算子來訂閱 委派的方法。 -= 運算子會取消訂閱委派的方法。 在 C# 中,您可以使用 += 運算子來訂閱事件的方法,或訂閱未與 event 關鍵字搭配使用的委派 委派包含所有物件的參考,這些物件具有訂閱委派的方法。 當委派保留這些參考時,這些物件不符合記憶體回收的資格。
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# 範例

本節包含上一個 X++ 範例之事件設計模式的 C# 程式碼範例。

// 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 中的事件處理常式節點。

比較:預編譯器指令

X++ 和 C# 共用一些用於其前置編譯器指示詞語法的關鍵字,但意義並不總是相同的。

相似之處

X++ 和 C# 編譯器可辨識許多相同的關鍵字。 在大部分情況下,關鍵字對於兩種語言編譯器的意義相同。

Differences

X++ 與 C# 中的預編譯器指令之間的根本區別是兩種語言預編譯器都可識別的 #define 關鍵字。 與 C# 不同,在 X++ 中,#define 指令的語法中需要一個點。 在 X++ 中,括號可用來為定義的符號提供值。 這些差異顯示在下列範例中:

  • 在 X++ 中:#define。初始年份(2003)
  • 在 C# 中:#define InitialYear

一個細微的區別是,在 C# 中,# 字元和指令關鍵字之間可以有空格和製表符,例如 # define Testing。

相同的關鍵字

下表列出 X++ 和 C# 中類似的前置編譯器指示詞。

Keyword X++的 C# 評論
#define 在 X++ 中,可以定義前編譯器變數名稱,並可以為該變數提供值。 在 C# 中,可以定義預編譯器變數名稱,但無法為該變數提供任何值。 此外,C# 中的任何 #define 都必須發生在檔案頂端,而且不能發生在任何程式碼之後,例如 using 陳述式或類別宣告。 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 X++ 中沒有 #else 指令,但 #ifnot 提供了類似的功能。 在 X++ 中,#ifnot 可以判斷前置編譯器變數是否存在,以及變數是否沒有特定的指定值。 在 C# 中,#if 可以確定當 '!' symbol 的字首是變數名稱的前置詞。
//BP Deviation documented #pragma 警告 這些 X++ 和 C# 項目並不等同,但有部分相似性。 兩者都會隱藏編譯器警告訊息。
#macrolib .C++ 中的 HPP 檔案 X++ 指令 #macrolib 與 .HPP 檔案。 兩者都可以包含數個 #define 陳述式。

X++ 獨有的預編譯器指令

下表列出 C# 中沒有直接對應專案的 X++ 前置編譯器指示詞。

X++的 評論
#linenumber #linenumber 指令用於獲取行號,以便將其輸出到信息日誌。
C# 指令 #line 不同,因為它的目的是設定行號。
#defdec #definc
#globaldefine 在 X++ 中,#globaldefine 與 #define 之間存在微小差異。 差異在於 #globaldefine 永遠不會覆寫 #define 指派給前置編譯器變數的目前非空值。
C# 與此差異沒有任何類似之處,因為在 C# 中,無法為前編譯器變數名稱指定值。
#localmacro #巨集 在 X++ 中,#localmacro 可讓您將多行值指派給前置編譯器變數。 #巨集 是同義詞,但建議 #localmacro。
在 C# 中,#define 指令具有此功能的一部分,但它無法將值指派給前置編譯器變數。
#globalmacro 在 X++ 中,#globalmacro 與首選 #localmacro 幾乎相同。

比較:物件導向程式設計

X++ 的物件導向程式設計 (OOP) 原則與 C# 不同。

概念比較

下表比較了 X++ 和 C# 之間 OOP 原則的實作。

特徵 / 功能 X++的 C# 評論
鑄造 X++ 語言具有關鍵字 isas,用於使下播安全且明確。 提示: 當您將基類變數降譯為衍生類別變數時,X++ 不需要使用 as 關鍵字。 不過,我們建議所有向下轉換陳述式都使用 as 關鍵字。 物件可以在繼承路徑上或向下轉換。 向下轉換需要 as 關鍵字。 如需 X++ 關鍵字 isas 的詳細資訊,請參閱 運算式運算子:繼承的 Is 和 As。
區域函式 方法可以包含零個或多個本機函式的宣告和程式碼本文。 只有該方法可以呼叫本機函式。 C# 3.0 支援 lambda 運算式,其與匿名函式和本機函式有一些相似之處。 Lambda 運算式通常與委派一起使用。
方法多載 不支援方法多載。 每個類別只能出現一次方法名稱。 支援方法重載。 一個方法名稱可以在一個類別中出現多次,在每種情況下都有不同的參數簽章。 X++ 確實支援方法上的可選參數。 選擇性參數可以部分模擬方法多載。 如需詳細資訊,請參閱此表格中選用參數的資料列。
方法覆寫 支援方法覆寫。 衍生類別可以具有與基底類別中名稱相同的方法,只要參數簽章在這兩種情況下都相同即可。 唯一的例外是覆寫方法可以將預設值新增至參數。 支援方法覆寫。 虛擬 關鍵字必須 套用至方法,才能在衍生類別中覆寫方法。 覆寫方法的概念包括方法名稱、其參數簽章及其傳回類型。 如果基底方法和覆寫方法在任何這些方面不同,則方法覆寫的概念不適用。
選擇性參數 參數宣告後面可以接著預設值指派。 方法呼叫端可以選擇傳遞該參數的值,或忽略參數以接受預設值。 此功能會模擬方法多載,因為對相同方法名稱的兩次呼叫可以傳遞不同數目的參數。 每個具有預設值的參數都必須遵循沒有預設值的最後一個參數。 params 關鍵字支援選用參數。 即使沒有 params 關鍵字,從呼叫者的角度來看,方法重載也可以提供部分類似的功能。 如需詳細資訊,請參閱參數和範圍設定和使用選擇性參數。
單一繼承 您可以在 AOT 中,使用類別的 classDeclaration 節點中的 extends 關鍵字,從另一個 X++ 類別衍生 X++ 類別。 沒有任何類別隱含地直接衍生自另一個類別。 如果想要類別直接衍生自類別 Object ,則必須使用 extends 關鍵字。 您只能在 extends 關鍵字上指定一個類別。

注意: 當您修改其他類別衍生的 X++ 基類時,您必須使用「向前編譯」來重新編譯該基類。 此選項可確保衍生類別也會重新編譯。 若要確保衍生類別也重新編譯,請以滑鼠右鍵按一下基底類別節點,然後按一下 Add-Ins > [向前編譯]。 按一下 [建置 > 編譯] (或按 F7 鍵) 的替代方法有時不足以變更基底類別。

一個類別可以實作零到多個介面。

X++ 資料表隱含地繼承 Common 自資料表和 xRecord 類別。
C# 使用 extends 關鍵字從另一個類別衍生。 所有 .NET Framework 類別都會隱含地衍生自該 System.Object 類別,除非它們明確衍生自另一個類別。

關鍵字比較

下表列出 X++ 和 C# 中的 OOP 相關關鍵字。

Keyword X++的 C# 評論
abstract 沒有區別。
類別 修飾詞 publicprivate 在類別宣告上會被忽略。 沒有類別命名空間分組的概念。 任何類別名稱中都沒有點 (.) 。 修飾符 publicprivate 可以用來修改類別宣告。 C# 也有關鍵字 internal,它與如何在組合檔案中將類別分組在一起有關。 沒有 受保護 類別的概念,只有類別的 受保護 成員。
延伸 類別宣告可以使用 extends 關鍵字繼承自另一個類別。 冒號 (:) 用於關鍵字 extendsimplements 在 X++ 中使用的地方。
最終方法無法在衍生類別中覆寫。 期末課程無法延長。 類別上的關鍵字 sealed 的含義與 final 在X++類別上的含義相同。
類別宣告可以使用implements關鍵字來實作介面
interface 介面可以指定類別必須實作的方法。 介面可以指定類別必須實作的方法。
new 關鍵字可用來配置類別的新實例。 然後自動呼叫建構函式。 每個類別只有一個建構函式,建構函式名為 new。 您可以決定建構函式應該輸入哪些參數。 new 關鍵字用於建立類別的新實例。 然後自動呼叫建構函式。 建構函數方法本身沒有命名 new,它們與類別具有相同的名稱。

便條:new 關鍵字也可以用於方法,以修改方法覆寫基類中相同方法的方式。

X++ 和 C# 都假設其程式碼中沒有明確撰寫建構函式的類別的預設建構函式。
沒有區別。
私密受保護 privateprotected 關鍵字可用來修改類別成員的宣告。 privateprotected 關鍵字可用來修改類別成員的宣告。
public 未使用 publicprotectedprivate 修改的方法具有預設存取層級 public 未使用 publicprotectedprivate 修改的方法具有預設存取層級 private
靜態 方法可以是 靜態的,但欄位不能。 方法和欄位都可以是 靜態的
超級 super 關鍵字用於衍生類別中,以存取其基類上的相同方法。 void method2()
{
// Call method2 method
// on the base class.
super();
}
base 關鍵字在衍生類別中用於存取其基類別中的各種方法。
void method2()
{
// Call methods on
// the base class.
base.method2();
base.method3();
}
在 C# 中,有使用 base 呼叫 base 建構函式的特殊語法。
對於從一個實例方法呼叫相同物件上的另一個實例方法,需要呼叫方法的限定詞。 關鍵字 this 可作為目前物件的限定詞。 對於從一個實例方法呼叫相同物件上的另一個實例方法,不需要呼叫方法的限定詞。 不過, this 關鍵字可作為目前物件的限定詞。 實際上,關鍵字 this 可以透過顯示 IntelliSense 資訊來提供協助。
finalize Object 類別包含方法 finalize 。 該 finalize 方法不是 最終的,可以被覆蓋。 該 finalize 方法看起來 System.Object.Finalize 類似於 C# 中的方法,但在 X++ 中,該 finalize 方法沒有任何特殊意義。 當物件的最後一個參考停止參考物件時,物件會自動從記憶體中移除。 例如,當最後一個參考超出範圍或被指派另一個物件進行參考時,就會發生這種情況。 這些方法 FinalizeDispose 在某些類型的類別上很常見。 垃圾收集器在銷毀和物件時呼叫 and FinalizeDispose 方法。 在 C# 中, System.GC.Collect 可以呼叫 .NET Framework 中的方法來啟動垃圾收集器。 X++ 中沒有類似的函式,因為 X++ 使用確定性記憶體回收器。
main 從功能表呼叫的類別會由 main 系統呼叫其方法。 從指令行主控台呼叫的類別會由 Main 系統呼叫其方法。

比較:類別

當您在 .NET Framework 中使用 C# 時,類別會分組到命名空間中。 每個命名空間都專注於一個功能區域,例如檔案操作或反射。 不過,當您在 X++ 中使用類別時,沒有像命名空間這樣的可見群組。

比較:關於反思的課程

在 X++ 中,類別 TreeNode 提供應用程式物件樹狀結構 (AOT) 的存取權。 該 TreeNode 類是 X++ 中反射功能的中心。 TreeNode類別及其方法可以與 C# 使用的 .NET Framework 中的命名空間進行System.Reflection比較。

下表列出您在撰寫 C# 程式碼時可用的數個類別。 這些是 .NET Framework 類別。 對於此資料表,除非另有指定,否則所有 C# 類別都位於命名空間中 System.Reflection 。 每一列都會顯示您在撰寫 X++ 程式碼時可用的對應類別或類別成員。

X++的 C# 評論
TreeNode System .Assembly 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和完成導航的方法AOTfirstChildAOTnextSibling。 作為對等的替代方案,X++ AOTiterator 類別的設計目的是要流覽 AOT 的樹狀結構控制項。 類別節點是數個方法節點的父節點。 AOTiterator子節點的步驟,將每個節點傳回為另一個TreeNode實例。 其他資源 已命名 TreeNodeAOTparent的方法。AOTprevious
TreeNode .AOTgetProperty TreeNode .AOTgetProperties TreeNode .AOTname PropertyInfo 在 X++ 中,方法 AOTgetProperties 會傳回一個長字串,其中包含 的所有 TreeNode屬性的名稱值對。 此 AOTname 方法會傳回僅包含 name 屬性值的字串。
TreeNode .AOTsave TreeNode .AOTinsert System .Reflection .Emit (類別的命名空間) AOTsave 方法會將 X++ 程式碼中物件的 TreeNode 變更套用至 AOT,而且會保存變更。 如需大型程式碼範例,請參閱 TreeNode.AOTsave 方法。

比較:有關檔案 IO 的類別

有數個類別會執行檔案輸入和輸出 (IO) 作業。 在 C# 中使用的 .NET Framework 中,這些類別的對應類別位於命名空間中 System.IO

下表列出命名空間中的 System.IO 數個 C# .NET Framework 類別。 表格中的每一列都會顯示最符合 .NET Framework 類別的 X++ 類別或方法。

X++的 C# 評論
BinaryIo FileStream BinaryReader BinaryWriter X++ 類別(例如 BinaryIo 從抽象類別 Io 延伸)可作為資料流程,而且也可作為該資料流程的讀取器和寫入器。 在 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
assertdemand 的概念和方法revertAssert適用於這兩種語言。 不過, deny C# 中可用的 and revertDeny 方法在 X++ 中無法使用。

X++、ANSI SQL 比較:SQL 選擇

在 X++ 中,SQL select 陳述式語法與美國國家標準協會 (ANSI) 規格不同。

單桌選擇

下表列出 X++ SQL 和 ANSI SQL 的 select 陳述式之間的差異。

特徵 / 功能 X++ SQL ANSI SQL 評論
from 子句上的表格名稱。 from 子句會列出從資料表宣告的記錄緩衝區實例,例如從資料表宣CustTable告。 from 子句會列出資料表名稱,而不是緩衝區的名稱。 記錄緩衝區具有類別在 xRecordX++ 中的所有方法。
order by 與 where 子句的語法順序。 order by 子句必須出現在 where 子句之前。 order by 子句必須出現在 fromjoin 子句之後。 group by 子句必須遵循與順序 by 遵循的相同語法定位規則。 order by 子句必須出現在 where 子句之後。 where 子句必須出現在 fromjoin 子句之後。 在 X++ 和 ANSI SQL 中, fromjoin 子句必須出現在 order by 和 where 子句之前。
條件否定。 感嘆號 ('!') 用於否定。 not 關鍵字用於否定。 X++ 不支援語法 !like。 相反地,您必須套用 ! 運算子新增至子句。
like 運算子的萬用字元。 0 到多 – 星號 ('*')
恰好 1 – 問號 ('?')
0 到多 – 百分號 ('%')
恰好 1 – 下桿 ('_')
where 子句中的邏輯運算子。 並且 – & &
或者 – ||
還有——
或 –

程式碼範例

下列程式碼範例說明上表中的功能。

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 的關鍵字:

  • 跨公司
  • 第一只100
  • 強制文字
  • forcenested迴圈
  • 強制預留位置
  • 強制選取順序
  • ValidTime狀態

join 子句

下表列出 X++ SQL 和 ANSI SQL join 關鍵字的 差異。

特徵 / 功能 X++ SQL ANSI SQL 評論
欄清單。 直欄清單中的直欄必須全部來自 from 子句中列出的表格,而不是 來自聯結 子句中的任何表格。 清單中的資料行無法以其資料表名稱來限定。 直欄清單中的直欄可以來自 fromjoin 子句中的任何表格。 當您使用資料表名稱限定清單中的資料行時,它可協助其他人維護您的程式碼。 如需詳細資訊,請參閱選取欄位上的陳述式。
join 子句語法。 join 子句會遵循 where 子句。 join 子句會遵循 from 子句中的表格。 在 X++ 程式碼範例中, 聯結 準則是值相 SalesPoolId 等。
Inner 關鍵字。 預設 聯結 模式為內部聯結。 沒有 內在 關鍵字。 預設 聯結 模式為內部聯結。 內部關鍵字可用來明確化程式碼。 外部關鍵字同時存在於 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 之間參考 選取 資料行清單中彙總欄位的一些差異。 彙總欄位是由 sumavg 等函數衍生的欄位。

特徵 / 功能 X++ SQL ANSI SQL 評論
彙總欄位名稱別名。 彙總值位於彙總的欄位中。 您可以使用 as 關鍵字,以名稱別名標記彙總欄位。 別名可以在後續程式碼中參考。 如需詳細資訊,請參閱彙總函式:X++ 和 SQL 之間的差異

程式碼範例

在下列程式碼範例中,對 info 方法的呼叫說明參考彙總欄位的方式 (請參閱 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.
***/

其他差異

下表列出 X++ SQL 與 ANSI SQL 之間 select 陳述式的其他差異。

特徵 / 功能 X++ SQL ANSI SQL 評論
having 關鍵字。 沒有 having 關鍵字。 having 關鍵字可讓您指定 group by 子句所產生列的過濾準則。 沒有評論。
Null 結果。 while select 陳述式中,如果 where 子句過濾掉所有資料列,則不會傳回任何特殊計數資料列來報告該資料列。 選取專案中,如果 where 子句篩選掉所有資料列,則會傳回特殊的計數資料列。 計數值為 0。 沒有評論。
用於導覽傳回資料列的游標。 while select 陳述式提供游標功能。 另一種方法是使用 下一個 關鍵字。 您可以宣告 游標 ,以迴圈從 select 陳述式傳回的列。
From 子句。 當未列出任何資料行且僅參考一個表格時, from 關鍵字是選用的。 下列兩個語法選項是對等的:
select \* from tCustTable;
select tCustTable;
select 陳述式無法從資料表讀取,除非使用 from 子句。 在 X++ SQL 中,簡式 select 陳述式會以傳回的第一列填入表格緩衝區變數。 以下程式碼片段說明了這一點:
select \* from tCustTable;
info(tCustTable.Name);