Respuestas:
Metadatos Datos sobre sus objetos / métodos / propiedades.
Por ejemplo, podría declarar un Atributo llamado: DisplayOrder para poder controlar fácilmente en qué orden deberían aparecer las propiedades en la IU. Luego podría agregarlo a una clase y escribir algunos componentes de la GUI que extraen los atributos y ordenan los elementos de la interfaz de usuario de manera adecuada.
public class DisplayWrapper
{
private UnderlyingClass underlyingObject;
public DisplayWrapper(UnderlyingClass u)
{
underlyingObject = u;
}
[DisplayOrder(1)]
public int SomeInt
{
get
{
return underlyingObject .SomeInt;
}
}
[DisplayOrder(2)]
public DateTime SomeDate
{
get
{
return underlyingObject .SomeDate;
}
}
}
De este modo, me aseguro de que SomeInt siempre se muestre antes de SomeDate cuando trabajo con mis componentes GUI personalizados.
Sin embargo, los verá más comúnmente utilizados fuera del entorno de codificación directa. Por ejemplo, el Diseñador de Windows los usa ampliamente, por lo que sabe cómo tratar con objetos personalizados. Usando el atributo BrowsableAttribute de esta manera:
[Browsable(false)]
public SomeCustomType DontShowThisInTheDesigner
{
get{/*do something*/}
}
Le dice al diseñador que no enumere esto en las propiedades disponibles en la ventana Propiedades en tiempo de diseño, por ejemplo.
También puede usarlos para la generación de código, operaciones de precompilación (como Post-Sharp) u operaciones de tiempo de ejecución como Reflection.Emit. Por ejemplo, podría escribir un poco de código para crear un perfil que envuelva de forma transparente cada llamada que haga su código y lo cronometre. Puede "optar por no participar" del tiempo a través de un atributo que coloca en métodos particulares.
public void SomeProfilingMethod(MethodInfo targetMethod, object target, params object[] args)
{
bool time = true;
foreach (Attribute a in target.GetCustomAttributes())
{
if (a.GetType() is NoTimingAttribute)
{
time = false;
break;
}
}
if (time)
{
StopWatch stopWatch = new StopWatch();
stopWatch.Start();
targetMethod.Invoke(target, args);
stopWatch.Stop();
HandleTimingOutput(targetMethod, stopWatch.Duration);
}
else
{
targetMethod.Invoke(target, args);
}
}
Declararlos es fácil, solo crea una clase que herede de Attribute.
public class DisplayOrderAttribute : Attribute
{
private int order;
public DisplayOrderAttribute(int order)
{
this.order = order;
}
public int Order
{
get { return order; }
}
}
Y recuerde que cuando usa el atributo puede omitir el sufijo "atributo", el compilador lo agregará por usted.
NOTA: Los atributos no hacen nada por sí mismos; es necesario que haya algún otro código que los use. Algunas veces ese código ha sido escrito para ti, pero a veces tienes que escribirlo tú mismo. Por ejemplo, el compilador de C # se preocupa por algunos y ciertos frameworks usan algunos (por ejemplo, NUnit busca [TestFixture] en una clase y [Test] en un método de prueba al cargar un ensamblaje).
Por lo tanto, al crear su propio atributo personalizado, tenga en cuenta que no afectará en absoluto el comportamiento de su código. Deberá escribir la otra parte que verifica los atributos (a través de la reflexión) y actuar sobre ellos.
Mucha gente ha respondido pero nadie ha mencionado esto hasta ahora ...
Los atributos se usan mucho con la reflexión. La reflexión ya es bastante lenta.
Vale la pena marcar sus atributos personalizados como sealed
clases para mejorar su rendimiento en tiempo de ejecución.
También es una buena idea considerar dónde sería apropiado usar colocar tal atributo y atribuir su atributo (!) Para indicar esto a través de AttributeUsage
. La lista de usos de atributos disponibles puede sorprenderle:
También es genial que el atributo AttributeUsage sea parte de la firma del atributo AttributeUsage. ¡Vaya por dependencias circulares!
[AttributeUsageAttribute(AttributeTargets.Class, Inherited = true)]
public sealed class AttributeUsageAttribute : Attribute
Los atributos son un tipo de metadatos para etiquetar clases. Esto se usa a menudo en WinForms, por ejemplo, para ocultar controles de la barra de herramientas, pero se puede implementar en su propia aplicación para permitir que las instancias de diferentes clases se comporten de maneras específicas.
Comience creando un atributo:
[AttributeUsage(AttributeTargets.Class, AllowMultiple=false, Inherited=true)]
public class SortOrderAttribute : Attribute
{
public int SortOrder { get; set; }
public SortOrderAttribute(int sortOrder)
{
this.SortOrder = sortOrder;
}
}
Todas las clases de atributos deben tener el sufijo "Atributo" para ser válido.
Una vez hecho esto, cree una clase que use el atributo.
[SortOrder(23)]
public class MyClass
{
public MyClass()
{
}
}
Ahora puede verificar una clase específica ' SortOrderAttribute
(si tiene una) haciendo lo siguiente:
public class MyInvestigatorClass
{
public void InvestigateTheAttribute()
{
// Get the type object for the class that is using
// the attribute.
Type type = typeof(MyClass);
// Get all custom attributes for the type.
object[] attributes = type.GetCustomAttributes(
typeof(SortOrderAttribute), true);
// Now let's make sure that we got at least one attribute.
if (attributes != null && attributes.Length > 0)
{
// Get the first attribute in the list of custom attributes
// that is of the type "SortOrderAttribute". This should only
// be one since we said "AllowMultiple=false".
SortOrderAttribute attribute =
attributes[0] as SortOrderAttribute;
// Now we can get the sort order for the class "MyClass".
int sortOrder = attribute.SortOrder;
}
}
}
Si desea leer más sobre esto, siempre puede consultar MSDN, que tiene una descripción bastante buena.
¡Espero que esto te haya ayudado!
Un atributo es una clase que contiene algunas funcionalidades que puede aplicar a los objetos en su código. Para crear uno, cree una clase que herede de System.Attribute.
En cuanto a para qué son buenos ... hay usos casi ilimitados para ellos.
Los atributos son como metadatos aplicados a clases, métodos o ensamblajes.
Son buenos para cualquier cantidad de cosas (visualización del depurador, marcar cosas como obsoletas, marcar cosas como serializables, la lista es interminable).
Crear tus propios personalizados es fácil como un pastel. Empieza aqui:
http://msdn.microsoft.com/en-us/library/sw480ze8(VS.71).aspx
En el proyecto en el que estoy trabajando actualmente, hay un conjunto de objetos de interfaz de usuario de varios tipos y un editor para ensamblar estos objetos para crear páginas para usar en la aplicación principal, un poco como el diseñador de formularios en DevStudio. Estos objetos existen en su propio ensamblaje y cada objeto es una clase derivada UserControl
y tiene un atributo personalizado. Este atributo se define así:
[AttributeUsage (AttributeTargets::Class)]
public ref class ControlDescriptionAttribute : Attribute
{
public:
ControlDescriptionAttribute (String ^name, String ^description) :
_name (name),
_description (description)
{
}
property String ^Name
{
String ^get () { return _name; }
}
property String ^Description
{
String ^get () { return _description; }
}
private:
String
^ _name,
^ _description;
};
y lo aplico a una clase como esta:
[ControlDescription ("Pie Chart", "Displays a pie chart")]
public ref class PieControl sealed : UserControl
{
// stuff
};
que es lo que han dicho los carteles anteriores.
Para usar el atributo, el editor tiene un que Generic::List <Type>
contiene los tipos de control. Hay un cuadro de lista desde el cual el usuario puede arrastrar y soltar en la página para crear una instancia del control. Para completar el cuadro de lista, obtengo el ControlDescriptionAttribute
para el control y completo una entrada en la lista:
// done for each control type
array <Object ^>
// get all the custom attributes
^attributes = controltype->GetCustomAttributes (true);
Type
// this is the one we're interested in
^attributetype = ECMMainPageDisplay::ControlDescriptionAttribute::typeid;
// iterate over the custom attributes
for each (Object ^attribute in attributes)
{
if (attributetype->IsInstanceOfType (attribute))
{
ECMMainPageDisplay::ControlDescriptionAttribute
^description = safe_cast <ECMMainPageDisplay::ControlDescriptionAttribute ^> (attribute);
// get the name and description and create an entry in the list
ListViewItem
^item = gcnew ListViewItem (description->Name);
item->Tag = controltype->Name;
item->SubItems->Add (description->Description);
mcontrols->Items->Add (item);
break;
}
}
Nota: lo anterior es C ++ / CLI pero no es difícil convertirlo a C # (sí, lo sé, C ++ / CLI es una abominación pero es con lo que tengo que trabajar :-()
Puede poner atributos en la mayoría de las cosas y hay una amplia gama de atributos predefinidos. El editor mencionado anteriormente también busca atributos personalizados en las propiedades que describen la propiedad y cómo editarla.
Una vez que tenga la idea completa, se preguntará cómo vivió sin ellos.
Como se dijo, los atributos son relativamente fáciles de crear. La otra parte del trabajo es crear código que lo use. En la mayoría de los casos, utilizará la reflexión en tiempo de ejecución para modificar el comportamiento en función de la presencia de un atributo o sus propiedades. También hay escenarios en los que inspeccionará los atributos del código compilado para realizar algún tipo de análisis estático. Por ejemplo, los parámetros pueden estar marcados como no nulos y la herramienta de análisis puede usar esto como una pista.
Usar los atributos y conocer los escenarios apropiados para su uso es la mayor parte del trabajo.
Los atributos son, esencialmente, bits de datos que desea adjuntar a sus tipos (clases, métodos, eventos, enumeraciones, etc.)
La idea es que en tiempo de ejecución algún otro tipo / marco / herramienta consultará su tipo de información en el atributo y actuará sobre él.
Entonces, por ejemplo, Visual Studio puede consultar los atributos en un control de terceros para determinar qué propiedades del control deberían aparecer en el panel Propiedades en el momento del diseño.
Los atributos también se pueden usar en la programación orientada a aspectos para inyectar / manipular objetos en tiempo de ejecución en función de los atributos que los decoran y agregan validación, registro, etc. a los objetos sin afectar la lógica de negocios del objeto.
Puede usar atributos personalizados como una forma simple de definir valores de etiquetas en subclases sin tener que escribir el mismo código una y otra vez para cada subclase. Encontré un buen ejemplo conciso de John Waters sobre cómo definir y usar atributos personalizados en su propio código.
Hay un tutorial en http://msdn.microsoft.com/en-us/library/aa288454(VS.71).aspx
Para comenzar a crear un atributo, abra un archivo fuente C #, escriba attribute
y presione [TAB]. Se expandirá a una plantilla para un nuevo atributo.