Compartir a través de


Clases de atributo de X++

Nota:

Los grupos de interés de la comunidad ahora se han movido de Yammer a Microsoft Viva Engage. Para unirse a una comunidad viva Engage y participar en las últimas discusiones, rellene el formulario Solicitar acceso a Finance and Operations Viva Engage Community y elija la comunidad a la que desea unirse.

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

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

Los atributos se aplican a los controladores de delegados y métodos para asignar los controladores a esos destinos.

Creación de una clase de atributo

Una clase de atributo puede extender la clase SysAttribute directamente o puede extender cualquier descendiente de la clase SysAttribute . La clase SysAttribute no se puede usar como atributo porque se declara abstracta. En el ejemplo siguiente se muestra la declaración y el diseño de una clase de atributo normal que se puede 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.
}

Decoración de una clase con un atributo

En el ejemplo siguiente se muestra una clase y un método decorados con practiceAttribute proporcionados 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 del atributo 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.

Constructores de atributos

Puede habilitar la clase de atributo para almacenar metadatos personalizados cada vez que se usa para decorar 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 de un constructor de atributos produciría una excepción, no se encontraría la excepción al decorar una clase con el atributo . La excepción se encontraría más adelante cuando un proceso examina una clase para ver el atributo con el que está decorado. Es cuando se construye el atributo .

Convenciones de nomenclatura

Todas las clases de atributo tienen el sufijo Attribute en su nombre. El sufijo Attribute es la convención de nombre que se recomienda, pero no es un requisito del sistema. Puede determinar si una clase se extiende directamente desde SysAttribute seleccionando la clase en el Explorador de aplicaciones y revisando 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 la compilación debe producir un error 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 almacenado 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.
}

Reflexión de metadatos

La reflexión se usa para buscar los metadatos de atributo adjuntos a una clase. Las clases que se van a usar 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 reflejar los metadatos de atributo son los siguientes:

  • Método getAllAttributes
  • Método getAttribute
  • Método getAttributedClasses
  • Método getAttributes

Nota:

No hay ningún mecanismo para enumerar todos los métodos o clases adornados con un atributo determinado del código X++. Sin embargo, dado que el compilador de X++ registra esta información en la base de datos de referencia cruzada, la información se puede extraer desde allí.

Ejemplo de código de reflexión de metadatos

La clase DictMethod se usa para buscar el valor de metadatos de un atributo que es decoración en un método. En el ejemplo de código siguiente se usa la clase SysEntryPointAttribute como atributo . Acepta los valores de parámetro para el nombre del método y para el nombre de la clase que contiene el método . El método parmChecked es específico 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");
}
**************/