Классы атрибутов в X++

В этой статье описывается использование атрибутов в X++.

Атрибут — это класс nonabstract, который расширяет (наследует от) класс 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] в предыдущем примере.

Attribute constructors

Класс атрибутов можно включить для хранения специализированных метаданных каждый раз, когда он украшает класс, выполнив его конструктор параметров. Параметры конструктора должны быть литералами примитивных типов, таких как int,enum или str. Компилятор не создает экземпляр класса атрибутов. Он сохраняет имя класса атрибута, а также литеральные значения для конструктора. Таким образом, если логика в конструкторе атрибутов вызовет исключение, декорирование класса атрибутом не приводит к исключению. Исключение обнаруживается позже, когда процесс смотрит на класс, чтобы увидеть атрибут, с которым он украшен. Этот процесс происходит при построении атрибута.

Naming conventions

Все классы атрибутов имеют атрибут суффикса в их имени. Суффикс атрибута — это соглашение об имени, которое корпорация Майкрософт рекомендует, но это не является системным требованием. Вы можете определить, распространяется ли класс непосредственно из SysAttribute , выбрав класс в обозревателе приложений и просмотрите свойство Extends в окне свойств .

SysObsoleteAttribute

Система предоставляет несколько атрибутов, включая класс SysObsoleteAttribute . Одним из способов использования класса SysObsoleteAttribute является уведомление компилятора о том, что компиляция должна завершиться ошибкой, если определенный метод вызывается в исходном коде. Компилятор отклоняет компиляцию и отображает определенное сообщение, хранящееся в этом использовании атрибута. Класс SysObsoleteAttribute также можно использовать для уведомления компилятора выдавать предупреждающие сообщения вместо ошибок.

Пример кода SysObsoleteAttribute

[SysObsoleteAttribute("The Automobile class might have faster performance.", false)]
class Bicycle
{
    // Members of the Bicycle class go here.
}

Metadata reflection

Для поиска метаданных атрибута, присоединенных к классу, используется отражение. Классы, используемые для отражения атрибутов, выглядят следующим образом:

  • Класс DictClass — для классов и интерфейсов.
  • Класс DictMethod — для методов в классах, интерфейсах или таблицах.

В предыдущих классах отражения методы отражения для отражения метаданных атрибутов приведены следующим образом:

  • getAllAttributes method
  • getAttribute method
  • getAttributedClasses method
  • getAttributes method

Note

Нет механизма перечисления всех методов или классов, украшенных определенным атрибутом из кода 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");
}
**************/