注释
社区兴趣团体现已从 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。 |
? |
三元运算符采用三个表达式:expression1? expression2 : expression3。 如果 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;,它将在编译时失败,因为 Bank 和 Dialog 类没有彼此的继承关系。 编译器只对声明为 Object 类的变量的赋值执行一个小验证。 编译器验证要分配给 Object 变量的项是否为类的实例。 编译器不允许将表缓冲区的实例分配给 Object 变量。 此外,编译器不允许将基元数据类型(例如 int 或 str)分配给 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关键字的特殊方式as。
as当关键字用于在表之间执行无效的向下转换时,目标变量将引用不可用的非 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。 |
&& |
如果 expression1 和 expression2 均为 true,则关系运算符返回 true。 |
|| |
如果 expression1 或 expression2 为 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 |
| 逻辑(AND、 OR) |
&&
||
|
| 有條件的 | ? : |
同一行上的运算符具有相等的优先级。 如果表达式包含其中多个运算符,则从左到右计算该表达式,除非使用赋值运算符。 (赋值运算符从右到左计算。例如, && (逻辑)和AND(逻辑||OR)具有相同的优先级,并从左到右计算。 Therefore:
-
0 && 0 || 1等于1 -
1 || 0 && 0等于0.