Поделиться через


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

Замечание

Группы интересов сообщества теперь переехали из Yammer в Microsoft Viva Engage. Чтобы присоединиться к сообществу Viva Engage и принять участие в последних обсуждениях, заполните форму " Запрос доступа к финансам и операциям Viva Engage Community " и выберите сообщество, к которому вы хотите присоединиться.

В этой статье описывается использование атрибутов в 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. Компилятор не создает экземпляр класса атрибутов. Он сохраняет имя класса атрибута, а также литеральные значения для конструктора. Таким образом, если логика в конструкторе атрибутов вызовет исключение, исключение не будет найдено путем декорирования класса атрибутом. Исключение будет найдено позже, когда процесс смотрит на класс, чтобы увидеть атрибут, с которым он украшен. Это происходит при построении атрибута.

Соглашения об именах

Все классы атрибутов имеют атрибут суффикса в их имени. Суффикс атрибута — это соглашение об имени, которое мы рекомендуем, но не является системным требованием. Вы можете определить, распространяется ли класс непосредственно из 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.
}

Отражение метаданных

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

  • Класс 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");
}
**************/