Clases de atributos X++

En este artículo se describe el uso de atributos en X++.

Un atributo es una clase no abstracta que se extiende (hereda de) la clase SysAttribute . Los atributos representan o almacenan metadatos sobre tipos y métodos. Puedes adjuntar un atributo a una clase, un campo de clase, un método de clase, una interfaz o una tabla.

Aplica atributos a los manejadores de delegados y métodos para mapear los manejadores a esos objetivos.

Crear una clase de atributo

Una clase de atributo puede extender la clase SysAttribute directamente o puede extender cualquier descendiente de la clase SysAttribute . No puedes usar la clase SysAttribute como un atributo porque se declara abstracta. El siguiente ejemplo muestra la declaración y diseño de una clase de atributos ordinaria que puedes crear.

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.
}

Decorar una clase con un atributo

En el ejemplo siguiente se muestra una clase y un método decorados con el PracticeAttribute proporcionado en el ejemplo anterior. Si el constructor del atributo no toma parámetros, los paréntesis de los parámetros son opcionales. La decoración de atributos podría estar [AnotherAttribute] sin paréntesis.

[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.
}

Puede omitir el sufijo del nombre del atributo si el sufijo es Attribute. Por ejemplo, podría usar [Practice] en su lugar [PracticeAttribute] en el ejemplo anterior.

Attribute constructors

Puedes habilitar tu clase de atributo para almacenar metadatos personalizados cada vez que decore una clase haciendo que su constructor tome parámetros. Los parámetros del constructor deben ser literales de los tipos primitivos, como int,enum o str. El compilador no construye una instancia de la clase de atributo. Almacena el nombre de la clase de atributo, además de los valores literales de su constructor. Por lo tanto, si la lógica en un constructor de atributos lanzaría una excepción, decorar una clase con el atributo no causa la excepción. La excepción se encuentra más adelante cuando un proceso examina una clase para ver el atributo con el que está decorada. Ese proceso es cuando se construye el atributo.

Naming conventions

Todas las clases de atributos tienen el sufijo Attribute en su nombre. El sufijo Atributo es la convención de nombre que recomienda Microsoft, pero no es un requisito del sistema. Para determinar si una clase se extiende directamente desde SysAttribute , seleccione la clase en el Explorador de aplicaciones y revise la propiedad Extends en la ventana Propiedades .

SysObsoleteAttribute

El sistema proporciona varios atributos, incluida la clase SysObsoleteAttribute . Un uso de la clase SysObsoleteAttribute es notificar al compilador que se debe producir un error en la compilación si se llama a un método determinado en el código fuente. El compilador rechaza la compilación y muestra el mensaje específico que se almacena en este uso del atributo. La clase SysObsoleteAttribute también se puede usar para notificar al compilador que emita mensajes de advertencia en lugar de errores.

Ejemplo de código SysObsoleteAttribute

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

Metadata reflection

La reflexión se utiliza para buscar los metadatos de atributo que se adjuntan a una clase. Las clases que se van a utilizar para la reflexión de atributos son las siguientes:

  • Clase DictClass : para clases e interfaces.
  • Clase DictMethod : para métodos en clases, interfaces o tablas.

En las clases de reflexión anteriores, los métodos para reflexionar sobre los metadatos de atributo son los siguientes:

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

Note

No existe un mecanismo para listar todos los métodos o clases que están adornados con un atributo particular del código X++. Sin embargo, dado que el compilador X++ registra esta información en la base de datos de referencia cruzada, puedes extraer esta información desde allí.

Ejemplo de código de reflexión de metadatos

Utiliza la clase DictMethod para encontrar el valor de metadatos de un atributo que decora un método. En el ejemplo de código siguiente se usa la clase SysEntryPointAttribute como atributo. Acepta los valores de los parámetros para el nombre del método y para el nombre de la clase que contiene el método. El método parmChecked es particular de la clase SysEntryPointAttribute , y no se hereda de su clase base SysAttribute. Cada clase de atributo puede tener su propio nombre de método para sus metadatos.

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");
}
**************/