Estos atributos crean la metadata que se puede utilizar en el proceso de compilación, además de otros importantes usos, y de ahí su importancia el manejar estos elementos del lenguaje.
Los atributos son etiquetas declarativas, es decir información adicional. Esta información se puede recuperar en tiempo de ejecución por medio del mecanismo de reflexión. Pueden usarse atributos predefinidos o personalizarlos.
Los atributos pueden ser colocados en la mayoría de las declaraciones (aunque un atributo especifico podría estar restringido a los tipos de declaraciones). La sintaxis, define que se coloque entre paréntesis cuadrados adelante de la declaración de la entidad a la que se aplica, por ejemplo el atributo Conditional.
[Conditional("DEBUG")] public class myClaseDebug
Aplicación de los atributos
En ocasiones la aplicación de atributos puede resulta ambiguo, veamos el siguiente ejemplo
[MiAtributo] int miMetodo (string cadenaTexto)
En el ejemplo es necesario saber con certeza a quien se aplica el atributo, ya sea al método o al valor de retorno. Para resolver estas situaciones, existen elementos conocidos como "destinos" predeterminados.
Por omisión el atributo aplica al método:
[MiAtributo] int miMetodo
Puede reemplazarse por especificaciones explicitas, por ejemplo:
[method: MiAtributo ] int miMetodo
[return: OtroAtributo] int miMetodo
La sintaxis general es:
[destino: lista-de-atributos]
El destino (target), es uno de los posibles destino assembly, field, module, param, property, return o type. La lista de atributos, se refiere a los atributos a aplicar.
Declaración
|
Destinos posibles
|
---|---|
assembly | assembly [assembly: lista-atributos] |
module | module [module: lista-atributos] |
class | type |
struct | type |
interface | type |
enum | type |
delegate | type, return |
method | method, return |
parameter | param |
field | field |
property — indexer | property |
property — get accessor | method, return |
property — set accessor | method, param, return |
event — field | event, field, method |
event — property | event, property |
event — add | method, param |
event — remove | method, param |
Atributos Globales
La mayoria de los atributos se relacionan a elementos específicos de lenguaje, como clases o métodos; sin embargo, algunos atributos son globales - estos se aplican a un ensamblado completo o un módulo
[assembly: lista-tributos]
[module: lista-atributos]
Los atributos globales aparecen después de las declaraciones using y antes que las declaraciones de espacio de nombres o de tipo, pueden aparecer en cualquier cantidad de archivos fuente pero sólo para una compilación. Por ejemplo:
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyTitle("MiAplicacion")]
Otros atributos de uso más frecuente:
AssemblyCompanyAttribute
AssemblyConfigurationAttribute
AssemblyCopyrightAttribute
AssemblyCultureAttribute
AssemblyDescriptionAttribute
AssemblyProductAttribute
AssemblyTrademarkAttribute
NOTAAssemblyCopyrightAttribute
AssemblyCultureAttribute
AssemblyDescriptionAttribute
AssemblyProductAttribute
AssemblyTrademarkAttribute
En el uso cotidiano es posible retirar del nombre del atributo el sufijo Attribute sin mayor problema
Crear atributos personalizados
Es posible crear atributos personalizados creando una clase de tipo atributo, ésta se deriva directamente de System.Attribute, esto permite identificar definiciones de atributos como metadatos de forma rápida y sencilla. Enseguida un ejemplo.
using System;
namespace AtributosPersonalizados
{
/// <summary>
/// La clase crea un atributo personalizado y documenta al desarrollador que
/// creo la clase.
///
/// El uso de System.Attribute, como clase base
/// define que se trata de un atributo personalizado.
///
/// El uso de AttributeUsage, se define para validar que el atributo
/// Desarrollador solo se usara para clases y estructuras.
/// El parametro con nombre: AllowMultiple, permite que el atributo sea
/// de un solo uso o multiple.
/// </summary>
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Struct, AllowMultiple = true)]
public class Desarrollador: Attribute
{
string _nombre;
public string version;
/// <summary>
/// El constructor toma el nombre y define un valor
/// por omision para la versión.
/// </summary>
/// <param name="nombre"></param>
public Desarrollador(string nombre)
{
this._nombre = nombre;
this.version = "1.0.0.0";
}
}
// Ejemplo de la declaración de una clase con el uso del
// atributo personalizado
[Desarrollador("Pedro Perez", version ="2.0.0.0")]
public class ClaseConAtributoPersonalizado
{
}
class Program
{
static void Main(string[] args)
{
}
}
}
Esta tarea se realiza por medio del método GetCustomAttributes, el cual nos proporciona una matriz de objetos equivalentes a los atributos de código fuente, en tiempo de ejecución.
Enseguida un ejemplo del uso de del método GetCustomAttributes.
using System;
namespace AtributosPersonalizados
{
/// <summary>
/// La clase crea un atributo personalizado y documenta al desarrollador que
/// creo la clase.
///
/// El uso de System.Attribute, como clase base
/// define que se trata de un atributo personalizado.
///
/// El uso de AttributeUsage, se define para validar que el atributo
/// Desarrollador solo se usara para clases y estructuras.
/// El parametro con nombre: AllowMultiple, permite que el atributo sea
/// de un solo uso o multiple.
/// </summary>
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Struct, AllowMultiple = true)]
public class Desarrollador: Attribute
{
string _nombre;
public string version;
/// <summary>
/// El constructor toma el nombre y define un valor
/// por omision para la versión.
/// </summary>
/// <param name="nombre"></param>
public Desarrollador(string nombre)
{
this._nombre = nombre;
this.version = "1.0.0.0";
}
// Obtiene el nombre del desarrollador
public string NombreDesarrollador()
{
return _nombre;
}
}
// Ejemplo de la declaración de una clase con el uso del
// atributo personalizado
[Desarrollador("Pedro Perez", version ="2.0.0.0")]
public class ClaseConAtributoPersonalizado
{
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Información de la clase ClaseConAtributoPersonalizado");
Attribute[] atributosClase = Attribute.GetCustomAttributes(typeof(ClaseConAtributoPersonalizado));
foreach (Attribute atributo in atributosClase)
{
if(atributo is Desarrollador)
{
Desarrollador d = (Desarrollador)atributo;
Console.WriteLine(" Nombre: {0}, version: {1} ", d.NombreDesarrollador(), d.version);
}
}
Console.ReadKey();
}
}
}
Referencias:
https://msdn.microsoft.com/es-es/library/aa288182(v=vs.71).aspx
https://msdn.microsoft.com/es-es/library/aa287893(v=vs.71).aspx
https://msdn.microsoft.com/es-es/library/aa287991(v=vs.71).aspx