注释
社区兴趣团体现已从 Yammer 迁移到Microsoft Viva Engage。 若要加入 Viva Engage 社区并参与最新讨论,请填写 “请求访问财务和运营 Viva Engage 社区 ”表单,然后选择要加入的社区。
本文介绍 X++ 中的属性的使用。
属性是一个非抽象类,用于扩展 (继承自 ) SysAttribute 类。 属性表示或存储有关类型和方法的元数据。 可以将特性附加到类、类字段、类方法、接口或表。
属性应用于委托和方法的处理程序,以便将处理程序映射到这些目标。
创建属性类
特性类可以直接扩展 SysAttribute 类,也可以扩展 SysAttribute 类的任何后代。 SysAttribute 类不能用作属性,因为它被声明为抽象类。 下面的示例演示了可以创建的普通属性类的声明和设计。
public class PracticeAttribute extends SysAttribute
{
// Fields in the classDeclaration.
StartEnd startEndEnum;
str reason;
// Constructor.
public void new(StartEnd _startEndEnum, str _reason)
{
startEndEnum = _startEndEnum;
reason = _reason;
}
// Other methods can go here.
}
使用特性修饰类
下面的示例演示了一个类和一个用上一示例中给定的 PracticeAttribute 修饰的方法。 如果特性的构造函数不采用任何参数,则参数的括号是可选的。 属性修饰可以是 [AnotherAttribute] 没有括号。
[PracticeAttribute(StartEnd::End, "Use the RegularClass class at the end.")]
public class RegularClass
{
[PracticeAttribute(Startend::Start, "Use the rehearse method at the start.")]
public int rehearse()
{
// Logic goes here.
}
// More fields and methods belong here.
}
如果后缀为 Attribute.,则可以省略属性名称的后缀。 例如,可以在前面的示例中改[Practice]用[PracticeAttribute]。
属性构造函数
通过让属性类采用参数,可以在每次使用它来修饰类时存储定制的元数据。 构造函数的参数必须是基元类型的文本,例如 int、enum 或 str。 编译器不构造特性类的实例。 它存储特性类的名称,以及其构造函数的文本值。 因此,如果属性构造函数中的逻辑将引发异常,则通过使用特性修饰类来找不到异常。 稍后,当进程查看类以查看其修饰的属性时,会发现异常。 即构造特性时。
命名约定
所有属性类都具有其名称中的后缀 特性 。 属性后缀是我们建议的名称约定,但它不是系统要求。 可以通过选择应用程序资源管理器中的类并在“属性”窗口中查看 Extends 属性来确定类是否直接从 SysAttribute扩展。
SysObsoleteAttribute
系统提供多个属性,包括 SysObsoleteAttribute 类。 SysObsoleteAttribute 类的一种用法是通知编译器,如果源代码中调用了特定方法,编译应失败。 编译器拒绝编译,并显示存储在此属性中使用的特定消息。 SysObsoleteAttribute 类还可用于通知编译器发出警告消息而不是错误。
SysObsoleteAttribute 代码示例
[SysObsoleteAttribute("The Automobile class might have faster performance.", false)]
class Bicycle
{
// Members of the Bicycle class go here.
}
元数据反射
使用反射查找附加到类的属性元数据。 用于属性反射的类如下所示:
- DictClass 类 – 对于类和接口。
- DictMethod 类 – 对于类、接口或表上的方法。
在前面的反射类中,用于反映属性元数据的方法如下所示:
- getAllAttributes 方法
- getAttribute 方法
- getAttributedClasses 方法
- getAttributes 方法
注释
没有用于列出使用 X++ 代码中的特定属性装饰的所有方法或类的机制。 但是,由于 X++ 编译器在交叉引用数据库中记录此信息,因此可以从那里挖掘这些信息。
元数据反射代码示例
使用 DictMethod 类查找方法上修饰的属性的元数据值。 下面的代码示例使用 SysEntryPointAttribute 类作为属性。 它接受方法名称的参数值,以及包含该方法的类的名称。 parmChecked 方法尤其适用于 SysEntryPointAttribute 类,并且它不继承自其基类 SysAttribute。 每个属性类都可以为其元数据有自己的方法名称。
static public int MetadataOfSysEntryPointAttributeOnMethod
(
str _sNameOfClass,
str _sNameOfMethod
)
{
// Return Values:
// 0 == Has the attribute, its metadata value is false;
// 1 == Has the attribute, its metadata value is true;
// 2 == The method lacks the SysEntryPointAttribute.
int nReturnValue = -1,
nClassId;
boolean boolParmChecked;
DictMethod dm;
Object attributeAsObject;
SysEntryPointAttribute sepAttribute;
Global::info("Starting AttributeReflection"
+ " ::MetadataOfSysEntryPointAttributeOnMethod ....");
Global::info(strFmt
("Parameters are: _sNameOfClass = %1 , _sNameOfMethod = %2 .",
_sNameOfClass, _sNameOfMethod)
);
nClassId = Global::className2Id(_sNameOfClass);
dm = new DictMethod
(UtilElementType::ClassInstanceMethod,
nClassId,
_sNameOfMethod
);
attributeAsObject = dm.getAttribute("SysEntryPointAttribute");
if (attributeAsObject is SysEntryPointAttribute)
{
sepAttribute = attributeAsObject as SysEntryPointAttribute;
boolParmChecked = sepAttribute.parmChecked();
if (boolParmChecked)
nReturnValue = 1;
else
nReturnValue = 0;
Global::info(
strFmt("Return value is %1.",
nReturnValue)
);
}
else
{
nReturnValue = 2;
Global::error("Object is not a SysEntryPointAttribute??");
}
return nReturnValue;
}
/*** Output displayed in the Infolog.
Message (05:03:22 pm)
Starting AttributeReflection ::MetadataOfSysEntryPointAttributeOnMethod ....
Parameters are: _sNameOfClass = CustCustomerService , _sNameOfMethod = create .
Return value is 1.
***/
/**************
// Simple AOT > Jobs job to run the method.
static void AttributeReflection33Job(Args _args)
{
AttributeReflection::MetadataOfSysEntryPointAttributeOnMethod
("CustCustomerService", "create");
}
**************/