X++ 运算符

注释

社区兴趣团体现已从 Yammer 迁移到Microsoft Viva Engage。 若要加入 Viva Engage 社区并参与最新讨论,请填写 “请求访问财务和运营 Viva Engage 社区 ”表单,然后选择要加入的社区。

本文介绍 X++ 中支持的运算符。

赋值运算符

赋值更改变量或字段的值。 下表显示了 X++ 赋值运算符。 前缀和后缀运算符之间没有区别。

Operator Description
= 将等号右侧的表达式分配给左侧的变量。
+= 将当前变量值加上右侧的表达式分配给左侧的变量。
++ 将变量递增 1。
-= 将当前变量值减去左侧变量右侧的表达式。
-- 将变量递减 1。

赋值运算符的代码示例

// An example of assignment operators and their output. 
static void Example1()
{
    int i = 1;
    // Using the = operator. i is assigned the value of i, plus 1. i = 2.
    i = i + 1;
    info(strFmt("Example 1: The result is "), i); // The result is 2.
}

static void Example2()
{
    int i = 1;
    // Using the += operator. i is assigned the value of i, plus 1. 
    // i = 2 (i = i + 1).
    i += 1;
    info(strFmt("Example 2: The result is "), i); // The result is 2. 
}

static void Example3()
{
    int i = 1;
    // Using the ++ operator. i is incremented by 1, and then 
    // by 1 again in the second statement. The final value of i is 3.
    i++;
    ++i;
    info(strFmt("Example 3: The result is "), i); // The result is 3. 
}

static void Example4()
{
    int i = 1;
    // Using the -= operator. i is assigned the value of i minus 1. 
    // i = 0 (i = i - 1).
    i -= 1;
    info(strFmt("Example 4: The result is "), i); // The result is 0. 
}

static void Example5()
{
    int i = 1;
    // Using the -- operator. i is decremented by 1, and then by 
    // 1 again in the second statement. The final value of i is -1.
    i--;
    --i;
    info(strFmt("Example 5: The result is "), i); // The result is -1. 
}

算数运算符

使用算术运算符执行数值计算。 大多数运算符都是二进制运算符,并采用两个作数。 但是, not~) 运算符是一元运算符,只采用一个作数。 二进制运算符的语法: expression1算术Operator表达式2 一元运算符的语法: 算术Operator表达式 1

Operator Description
<< 左移运算符对 expression1 执行 expression2 左移(乘以 2)。
>> 右移运算符对 expression1 执行 expression2 右移(除以 2)。
* 法运算符将 expression1以 expression2
/ 法运算符将 expression1 除以 expression2
DIV 整数除法运算符按 expression2 执行 expression1 的整数除法。
MOD 整数余数运算符按 expression2 返回 expression1 的整数除法的余数。
~ not 运算符或一元运算符执行二进制非运算。
& 二进制 AND 运算符对 expression1 和 expression2 执行二进制和运算。
^ 二进制 XOR 运算符对 expression1 和 expression2 执行二进制 XOR 运算
| 二进制 OR 运算符对 expression1 和 expression2 执行二进制或运算。
+ 运算符将 expression1 添加到 expression2
- 运算符从 expression1 中减去 expression2
? 三元运算符采用三个表达式:expression1expression2expression3。 如果 expression1 为 true,则返回 expression2 。 否则,将返回 expression3

算术运算符的代码示例

int a = 1 << 4;      // Perform four left shifts on 1 (1*2*2*2*2). a=16.
int b = 16 >> 4;     // Perform four right shifts on 16 (16/2/2/2/2). b=1.
int c = 4 * 5;       // Multiply 4 by 5. c=20.
int d = 20 / 5;      // Divide 20 by 5. d=4.
int e = 100 div 21;  // Return the integer division of 100 by 21. e=4 (4*21 = 84, remainder 16).
int f = 100 mod 21;  // Return the remainder of the integer division of 100 by 21. f=16.
int g = ~1;          // Binary negate 1 (all bits are reversed). g=-2.
int h = 1 & 3;       // Binary AND. Return the bits that are in common in the two integers. h=1.
int i = 1 | 3;       // Binary OR. Return the bits that are set in either 1 or 3. i=3.
int j = 1 ^ 3;       // Binary XOR. Return the bits that are set in 1 and NOT set in 3, and vice versa. j=2.
int k = 1 + 3;       // Add 1 and 3. k=4.
int l = 3 - 1;       // Subtract 1 from 3. l=2.
int m = (400 > 4) ? 1 : 5;  // If 400>4, 1 is returned. Otherwise, 5 is returned. Because 400>4, 1 is returned. m=1.

表达式运算符

as表达式is运算符控制向下转换分配。 向下转换分配涉及类或表继承。 隐式向下转换的赋值语句可能会导致难以预测和诊断的错误。 可以使用关键字 as 使向下转换显式。 可以使用 is 关键字来测试向下转换在运行时是否有效。

as 关键字

as 关键字用于从基类变量向下转换到派生类变量的赋值。 该 as 关键字告知其他程序员和编译器,你认为向下转换在运行时有效。

  • 编译器报告缺少关键字的 as 向下转换赋值语句的错误。
  • 在运行时,如果向下转换无效,关键字 as 会导致向下转换赋值语句分配 null
  • is 关键字通常用于安全测试关键字是否 as 正常工作。

as 关键字的代码示例

在下面的代码示例中, DerivedClass 类扩展 了 BaseClass 类。 该代码示例在其 basec派生变量 之间包含两个有效赋值。 到 basec 的向上转换分配不需要 as 关键字,但 派生的 向下转换分配需要 as 关键字。 以下代码将编译并运行,而不会出错。

static void AsKeywordExample()
{
    // DerivedClass extends BaseClass.
    BaseClass basec;
    DerivedClass derivedc;
    // BottomClass extends DerivedClass.
    BottomClass bottomc;
    derivedc = new DerivedClass();
    // AS is not required for an upcast assignment like this.
    basec = derivedc;
    // AS is required for a downcast assignment like this.
    derivedc = basec as DerivedClass;
    bottomc = new BottomClass();
    // AS causes this invalid downcast to assign null.
    bottomc = basec as DerivedClass;
}

is 关键字

关键字 is 验证对象是否为指定类的子类型。 如果对象是类的子类型,或者该对象与类的类型相同,则 is 表达式返回 true 。 如果关键字表达式比较两种 is 类型,但两种类型都不是另一种类型的子类型,并且它们不是同一类型,则编译器将报告错误。 编译器报告两种类型之间的任何纯赋值语句的类似错误,其中两种类型都不是另一种类型的子类型,并且它们不是同一类型。 在运行时,引用基础对象的变量类型与 is 关键字无关。 关键字 is 使系统验证变量引用的对象,而不是引用对象的变量的声明类型。

is 关键字的代码示例

下面的代码示例演示了控制表达式返回 istrue 还是 false 的条件。 代码示例取决于 Form 类和 Query 类都扩展 TreeNode 类的事实。

// The compiler issues an error for the following code. 
// The compiler ascertains that the Form class and the Query class are not 
// part of the same inheritance hierarchy. Both the Form class and the Query class
// extend the TreeNode class, but neither Form nor Query is a subtype of the other.
Form myForm = new Form();
info(strFmt("%1", (myForm is Query)));

// The Infolog displays 0 during run time, where 0 means false. No supertype 
// object can be considered to also be of its subtype class.
TreeNode myTreeNode = new TreeNode();
info(strFmt("%1", (myTreeNode is Form)));

// The Infolog displays 0 during run time, where 0 means false. A null 
// reference causes the is expression to return false.
Form myForm;
info(strFmt("%1", (myForm is Form)));

// The Infolog displays 1 during run time, where 1 means true. 
// An object is an instance of its own class type.
Form myForm = new Form();
info(strFmt("%1", (myForm is Form)));

// The Infolog displays 1 during run time, where 1 means true. 
// Every subtype is also of its supertype.
Form myForm = new Form();
info(strFmt("%1", (myForm is TreeNode)));

// The Infolog displays 1 during run time, where 1 means true. 
// The type of the underlying object matters in the is expression,
// not the type of the variable that references the object.
Form myForm = new Form();
TreeNode myTreeNode;
myTreeNode = myForm; // Upcast.
info(strFmt("%1", (myTreeNode is Form)));

代码示例是和作为关键字

下面的代码示例包含关键字的典型用法 is 。 关键字as在验证is关键字是否成功后as使用。 在此示例中, is 关键字和 as 关键字大写,使其更可见。

static void IsKeywordExample() 
{
    DerivedClass derivedc;
    BaseClass basec;
    basec = new DerivedClass();  // An upcast.
    if (basec IS DerivedClass)
    {
        info("Test 1: (basec IS DerivedClass) is true. Good.");
        derivedc = basec AS DerivedClass;
    }
    basec = new BaseClass();
    if (!(basec IS DerivedClass))
    {
        info("Test 2: !(basec IS DerivedClass) is true. Good.");
    }
}

//Output to the Infolog
Test 1: (basec IS DerivedClass) is true. Good.
Test 2: (!(basec IS DerivedClass)) is true. Good.

对象类作为特殊情况

Object 类可以在继承功能中显示为特殊情况。 编译器绕过类型检查声明为 Object 类型的变量和从中声明为 Object 类型的赋值。 某些类继承自 Object 类,某些类继承自另一个类,某些类不从任何类继承。 尽管 Dialog 类不继承自任何类,但以下代码示例中的赋值和调用语句可以正常工作。 但是,如果赋值是 bank4 = dlog3;,它将在编译时失败,因为 BankDialog 类没有彼此的继承关系。 编译器只对声明为 Object 类的变量的赋值执行一个小验证。 编译器验证要分配给 Object 变量的项是否为类的实例。 编译器不允许将表缓冲区的实例分配给 Object 变量。 此外,编译器不允许将基元数据类型(例如 intstr)分配给 Object 变量。

static void ObjectExample()
{
    Bank bank4;
    Object obj2;
    Dialog dlog3 = new Dialog("Test 4.");
    obj2 = dlog3;  // The assignment does work.
    obj2.run(false);  // The call causes the dialog to appear.
    info("Test 4a is finished.");
}

Tables

所有表都直接从 Common system 表继承,除非它们显式继承自其他表。 无法实例化 Common 表。 它不存在于基础物理数据库中。 Common 表继承自 xRecord 类,但采用不适合关键字或is关键字的特殊方式asas当关键字用于在表之间执行无效的向下转换时,目标变量将引用不可用的非 null 实体。 任何取消引用目标变量的尝试都将导致停止程序的错误。

是和作为关键字和扩展数据类型

每个扩展数据类型都有 一个 Extends 属性。 此属性控件的继承样式与设计关键字的继承isas样式不同。

关系运算符

下表列出了可在 X++ 中使用的关系运算符。 大多数运算符都是二进制运算符,并采用两个作数。 但是, not!) 运算符是一元运算符,只采用一个作数。 二进制运算符的语法: expression1relationalOperatorexpression2 unary 运算符的语法: relationalOperatorexpression1

Operator Description
like 如果 expression1 类似于 expression2则 like 关系运算符返回 true
== 如果两个表达式相等, 则相等 关系运算符返回 true
>= 如果 expression1 大于或等于 expression2则大于或等于关系运算符返回 true
<= 如果 expression1 小于或等于 expression2则小于或等于关系运算符返回 true
> 如果 expression1 大于 expression2则大于关系运算符返回 true
< 如果 expression1 小于 expression2则小于关系运算符返回 true
!= 如果 expression1 不同于表达式 2(即不等于),则不相等的关系运算符返回 true
&& 如果 expression1expression2 均为 true,关系运算符返回 true
|| 如果 expression1expression2 为 true,或者两者均为 true,则或关系运算符返回 true。
! 或一元关系运算符否定表达式。 如果表达式为 false,则返回 true ;如果表达式为 true,则返回 false

like 运算符

运算符 like 可以用作 * 零个或多个字符的通配符,并 ? 用作一个字符的通配符。 作数的最大长度为 1,000 个字符。 运算符 like 由基础 SQL 进行评估,因此结果在不同安装上可能有所不同。 如果要比较的表达式包含文件路径,则必须在每个元素之间包括四个反斜杠,如以下示例所示。

select * from xRefpaths
where xRefPaths.Path like "\\\\Classes\\\\AddressSelectForm"

等于 (==) 运算符

使用 equal==) 运算符比较对象时,将比较对象引用,而不是对象本身。 如果比较两个对象(其中一个位于服务器上),另一个对象位于客户端上,则此行为可能会导致问题。 在这些情况下,应在 Object 类中使用相等方法。 可以重写此方法以指定两个对象相等的含义。 如果不重写 相等 方法,则比较与 相等 运算符==完成的比较相同。

关系运算符的代码示例

"Jones" like "Jo?es"  // Returns true, because the ? is equal to any single character.
"Fabrikam, Inc." like "Fa*"  // Returns true, because the * is equal to zero or more characters.
(( 42 * 2) == 84)  // Returns true, because 42*2 is equal to 84.
today() >= 1\1\1980  // Returns true, because today is later than January 1, 1980.
((11 div 10) >= 1)  // Returns true, because 11 div 10 is 1 (therefore, >= 1 is true).
(11<= 12)  // Returns true, because 11 is less than 12.
((11 div 10) > 1)  // Returns false, because 11 div 10 is 1.
(11 div 10) < 1)  // Returns false, because 11 div 10 is 1.
(11 != 12)  // Returns true, because 11 is not equal to 12.
(1 == 1) && (3 > 1)  // Returns true, because both expressions are true.

运算符优先级

复合表达式的计算顺序可能很重要。 例如, (x + y / 100) 给出不同的结果,具体取决于先执行加法还是除法。 可以使用括号 (()) 显式告知编译器应如何计算表达式。 例如,可以指定 (x + y) / 100。 如果未显式告知编译器要执行作的顺序,则顺序基于分配给运算符的优先级。 例如,除法运算符的优先级高于加法运算符。 因此,对于表达式 x + y / 100,编译器首先计算 y / 100 。 换句话说, x + y / 100 等效于 x + (y / 100)。 若要使代码易于阅读和维护,请明确说明。 使用括号指示应首先计算哪些运算符。 下表列出了优先级顺序的运算符。 运算符在表中出现越高,优先级越高。 先计算优先级较高的运算符,然后再计算优先级较低的运算符。 请注意,X++ 的运算符优先级与其他语言(如 C# 和 Java)的运算符优先级不同。

运算符组,优先级顺序 运营商
Unary - ~ !
乘法、移位 、按位排他 * / % DIV << >> & ^
累加性、位非独占 + - |
关系、相等性 < <= == != > >= like as is
逻辑(ANDOR && ||
有條件的 ? :

同一行上的运算符具有相等的优先级。 如果表达式包含其中多个运算符,则从左到右计算该表达式,除非使用赋值运算符。 (赋值运算符从右到左计算。例如, && (逻辑)和AND(逻辑||OR)具有相同的优先级,并从左到右计算。 Therefore:

  • 0 && 0 || 1 等于 1
  • 1 || 0 && 0 等于 0.