C# Language
Atributos
Buscar..
Creando un atributo personalizado
//1) All attributes should be inherited from System.Attribute
//2) You can customize your attribute usage (e.g. place restrictions) by using System.AttributeUsage Attribute
//3) You can use this attribute only via reflection in the way it is supposed to be used
//4) MethodMetadataAttribute is just a name. You can use it without "Attribute" postfix - e.g. [MethodMetadata("This text could be retrieved via reflection")].
//5) You can overload an attribute constructors
[System.AttributeUsage(System.AttributeTargets.Method | System.AttributeTargets.Class)]
public class MethodMetadataAttribute : System.Attribute
{
//this is custom field given just for an example
//you can create attribute without any fields
//even an empty attribute can be used - as marker
public string Text { get; set; }
//this constructor could be used as [MethodMetadata]
public MethodMetadataAttribute ()
{
}
//This constructor could be used as [MethodMetadata("String")]
public MethodMetadataAttribute (string text)
{
Text = text;
}
}
Usando un atributo
[StackDemo(Text = "Hello, World!")]
public class MyClass
{
[StackDemo("Hello, World!")]
static void MyMethod()
{
}
}
Leyendo un atributo
El método GetCustomAttributes
devuelve una matriz de atributos personalizados aplicados al miembro. Después de recuperar esta matriz, puede buscar uno o más atributos específicos.
var attribute = typeof(MyClass).GetCustomAttributes().OfType<MyCustomAttribute>().Single();
O iterar a través de ellos.
foreach(var attribute in typeof(MyClass).GetCustomAttributes()) {
Console.WriteLine(attribute.GetType());
}
GetCustomAttribute
método de extensión GetCustomAttribute
de System.Reflection.CustomAttributeExtensions
recupera un atributo personalizado de un tipo específico, puede aplicarse a cualquier MemberInfo
.
var attribute = (MyCustomAttribute) typeof(MyClass).GetCustomAttribute(typeof(MyCustomAttribute));
GetCustomAttribute
también tiene una firma genérica para especificar el tipo de atributo para buscar.
var attribute = typeof(MyClass).GetCustomAttribute<MyCustomAttribute>();
El argumento booleano inherit
se puede pasar a ambos métodos. Si este valor se establece en true
los antepasados del elemento también se inspeccionarán.
DebuggerDisplay Attribute
Agregar el atributo DebuggerDisplay
cambiará la forma en que el depurador muestra la clase cuando se pasa el cursor.
Las expresiones que están envueltas en {}
serán evaluadas por el depurador. Esta puede ser una propiedad simple como en la siguiente muestra o una lógica más compleja.
[DebuggerDisplay("{StringProperty} - {IntProperty}")]
public class AnObject
{
public int ObjectId { get; set; }
public string StringProperty { get; set; }
public int IntProperty { get; set; }
}
Agregando ,nq
antes del corchete de cierre, se eliminan las comillas al generar una cadena.
[DebuggerDisplay("{StringProperty,nq} - {IntProperty}")]
Aunque las expresiones generales están permitidas en {}
no se recomiendan. El atributo DebuggerDisplay
se escribirá en los metadatos del conjunto como una cadena. Las expresiones en {}
no se verifican para validez. Por lo tanto, un atributo DebuggerDisplay
contenga una lógica más compleja que, por ejemplo, alguna aritmética simple, podría funcionar bien en C #, pero la misma expresión evaluada en VB.NET probablemente no será sintácticamente válida y producirá un error al depurar.
Una forma de hacer que DebuggerDisplay
más DebuggerDisplay
lenguaje es escribir la expresión en un método o propiedad y llamarla en su lugar.
[DebuggerDisplay("{DebuggerDisplay(),nq}")]
public class AnObject
{
public int ObjectId { get; set; }
public string StringProperty { get; set; }
public int IntProperty { get; set; }
private string DebuggerDisplay()
{
return $"{StringProperty} - {IntProperty}"";
}
}
Uno podría querer que DebuggerDisplay
muestre todas o solo algunas de las propiedades y al depurar e inspeccionar también el tipo del objeto.
El ejemplo a continuación también rodea el método auxiliar con #if DEBUG
ya que DebuggerDisplay
se usa en los entornos de depuración.
[DebuggerDisplay("{DebuggerDisplay(),nq}")]
public class AnObject
{
public int ObjectId { get; set; }
public string StringProperty { get; set; }
public int IntProperty { get; set; }
#if DEBUG
private string DebuggerDisplay()
{
return
$"ObjectId:{this.ObjectId}, StringProperty:{this.StringProperty}, Type:{this.GetType()}";
}
#endif
}
Atributos de información del llamante
Los atributos de la información de la persona que llama se pueden usar para transmitir información sobre el invocador al método invocado. La declaración se ve así:
using System.Runtime.CompilerServices;
public void LogException(Exception ex,
[CallerMemberName]string callerMemberName = "",
[CallerLineNumber]int callerLineNumber = 0,
[CallerFilePath]string callerFilePath = "")
{
//perform logging
}
Y la invocación se ve así:
public void Save(DBContext context)
{
try
{
context.SaveChanges();
}
catch (Exception ex)
{
LogException(ex);
}
}
Observe que solo el primer parámetro se pasa explícitamente al método LogException
, mientras que el resto se proporcionará en el momento de la compilación con los valores relevantes.
El parámetro callerMemberName
recibirá el valor "Save"
: el nombre del método de llamada.
El parámetro callerLineNumber
recibirá el número de la línea en la que se LogException
llamada al método LogException
.
Y el parámetro 'callerFilePath' recibirá la ruta completa del archivo Save
método se declara en.
Leyendo un atributo desde la interfaz
No hay una forma sencilla de obtener atributos de una interfaz, ya que las clases no heredan atributos de una interfaz. Siempre que implemente una interfaz o anule miembros en una clase derivada, debe volver a declarar los atributos. Entonces, en el siguiente ejemplo, la salida sería True
en los tres casos.
using System;
using System.Linq;
using System.Reflection;
namespace InterfaceAttributesDemo {
[AttributeUsage(AttributeTargets.Interface, Inherited = true)]
class MyCustomAttribute : Attribute {
public string Text { get; set; }
}
[MyCustomAttribute(Text = "Hello from interface attribute")]
interface IMyClass {
void MyMethod();
}
class MyClass : IMyClass {
public void MyMethod() { }
}
public class Program {
public static void Main(string[] args) {
GetInterfaceAttributeDemo();
}
private static void GetInterfaceAttributeDemo() {
var attribute1 = (MyCustomAttribute) typeof(MyClass).GetCustomAttribute(typeof(MyCustomAttribute), true);
Console.WriteLine(attribute1 == null); // True
var attribute2 = typeof(MyClass).GetCustomAttributes(true).OfType<MyCustomAttribute>().SingleOrDefault();
Console.WriteLine(attribute2 == null); // True
var attribute3 = typeof(MyClass).GetCustomAttribute<MyCustomAttribute>(true);
Console.WriteLine(attribute3 == null); // True
}
}
}
Una forma de recuperar los atributos de la interfaz es buscarlos en todas las interfaces implementadas por una clase.
var attribute = typeof(MyClass).GetInterfaces().SelectMany(x => x.GetCustomAttributes().OfType<MyCustomAttribute>()).SingleOrDefault();
Console.WriteLine(attribute == null); // False
Console.WriteLine(attribute.Text); // Hello from interface attribute
Atributo obsoleto
System.Obsolete es un atributo que se usa para marcar un tipo o un miembro que tiene una mejor versión y, por lo tanto, no se debe usar.
[Obsolete("This class is obsolete. Use SomeOtherClass instead.")]
class SomeClass
{
//
}
En caso de que se use la clase anterior, el compilador mostrará la advertencia "Esta clase está obsoleta. Use SomeOtherClass en su lugar".