Lo he intentado muchas veces, pero todavía no puedo entender el uso de atributos personalizados (ya he revisado muchos enlaces).
¿Alguien puede explicarme un ejemplo muy básico de un atributo personalizado con código?
Lo he intentado muchas veces, pero todavía no puedo entender el uso de atributos personalizados (ya he revisado muchos enlaces).
¿Alguien puede explicarme un ejemplo muy básico de un atributo personalizado con código?
Respuestas:
Si bien el código para crear un atributo personalizado es bastante simple, es muy importante que comprenda qué atributos son:
Los atributos son metadatos compilados en su programa. Los atributos en sí mismos no agregan ninguna funcionalidad a una clase, propiedad o módulo, solo datos. Sin embargo, usando la reflexión, uno puede aprovechar esos atributos para crear funcionalidad.
Entonces, por ejemplo, veamos el Bloque de aplicación de validación , de la Biblioteca empresarial de Microsoft . Si observa un ejemplo de código, verá:
/// <summary>
/// blah blah code.
/// </summary>
[DataMember]
[StringLengthValidator(8, RangeBoundaryType.Inclusive, 8, RangeBoundaryType.Inclusive, MessageTemplate = "\"{1}\" must always have \"{4}\" characters.")]
public string Code { get; set; }
A partir del fragmento anterior, se podría suponer que el código siempre se validará, siempre que se cambie, de acuerdo con las reglas del Validador (en el ejemplo, tenga al menos 8 caracteres y como máximo 8 caracteres). Pero la verdad es que el atributo no hace nada; como se mencionó anteriormente, solo agrega metadatos a la propiedad.
Sin embargo, Enterprise Library tiene un Validation.Validate
método que examinará su objeto y, para cada propiedad, verificará si el contenido viola la regla informada por el atributo.
Entonces, así es como debe pensar acerca de los atributos: una forma de agregar datos a su código que luego podrían ser utilizados por otros métodos / clases / etc.
Empiece escribiendo una clase que se derive de Attribute :
public class MyCustomAttribute: Attribute
{
public string SomeProperty { get; set; }
}
Entonces podrías decorar cualquier cosa (clase, método, propiedad, ...) con este atributo:
[MyCustomAttribute(SomeProperty = "foo bar")]
public class Foo
{
}
y finalmente usarías la reflexión para buscarlo:
var customAttributes = (MyCustomAttribute[])typeof(Foo).GetCustomAttributes(typeof(MyCustomAttribute), true);
if (customAttributes.Length > 0)
{
var myAttribute = customAttributes[0];
string value = myAttribute.SomeProperty;
// TODO: Do something with the value
}
Puede limitar los tipos de destino a los que se puede aplicar este atributo personalizado mediante el atributo AttributeUsage :
/// <summary>
/// This attribute can only be applied to classes
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class MyCustomAttribute : Attribute
Cosas importantes que debe saber sobre los atributos:
var value = typeof(Foo).GetCustomAttributes<MyCustomAttribute>().First().SomeProperty;
Utilizando / copiando la gran respuesta de Darin Dimitrov , así es como acceder a un atributo personalizado en una propiedad y no en una clase:
La propiedad decorada [de clase Foo
]:
[MyCustomAttribute(SomeProperty = "This is a custom property")]
public string MyProperty { get; set; }
Obteniéndolo:
PropertyInfo propertyInfo = typeof(Foo).GetProperty(propertyToCheck);
object[] attribute = propertyInfo.GetCustomAttributes(typeof(MyCustomAttribute), true);
if (attribute.Length > 0)
{
MyCustomAttribute myAttribute = (MyCustomAttribute)attribute[0];
string propertyValue = myAttribute.SomeProperty;
}
También puede lanzar esto en un bucle y usar la reflexión para acceder a este atributo personalizado en cada propiedad de la clase Foo
:
foreach (PropertyInfo propertyInfo in Foo.GetType().GetProperties())
{
string propertyName = propertyInfo.Name;
object[] attribute = propertyInfo.GetCustomAttributes(typeof(MyCustomAttribute), true);
// Just in case you have a property without this annotation
if (attribute.Length > 0)
{
MyCustomAttribute myAttribute = (MyCustomAttribute)attribute[0];
string propertyValue = myAttribute.SomeProperty;
// TODO: whatever you need with this propertyValue
}
}
Muchas gracias a ti, Darin !!
object[] attribute = propertyInfo.GetCustomAttributes(typeof(???), true);
Solo quiero iterar sobre todos ellos y llamar a un método m1()
de cada atributo desconocido
La respuesta corta es para crear un atributo en c #, solo necesita heredarlo de la clase Attribute, solo esto :)
Pero aquí voy a explicar los atributos en detalle:
básicamente los atributos son clases que podemos usarlos para aplicar nuestra lógica a ensamblajes, clases, métodos, propiedades, campos, ...
En .Net, Microsoft ha proporcionado algunos atributos predefinidos como Obsolete o Validation Attributes como ([Required], [StringLength (100)], [Range (0, 999.99)]), también tenemos atributos como ActionFilters en asp.net que puede ser muy útil para aplicar nuestra lógica deseada a nuestros códigos (lea este artículo sobre filtros de acción si le apasiona aprenderlo)
otro punto, puede aplicar un tipo de configuración en su atributo a través de AttibuteUsage.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)]
Cuando decora una clase de atributo con AttributeUsage, puede decirle al compilador de c # dónde voy a usar este atributo: voy a usar esto en clases, en ensamblajes en propiedades o en ... y mi atributo puede usar varias veces en objetivos definidos (clases, ensamblajes, propiedades, ...) o no ?!
Después de esta definición sobre atributos, les voy a mostrar un ejemplo: Imagine que queremos definir una nueva lección en la universidad y queremos permitir que solo los administradores y maestros de nuestra universidad definan una nueva lección, ¿de acuerdo?
namespace ConsoleApp1
{
/// <summary>
/// All Roles in our scenario
/// </summary>
public enum UniversityRoles
{
Admin,
Master,
Employee,
Student
}
/// <summary>
/// This attribute will check the Max Length of Properties/fields
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)]
public class ValidRoleForAccess : Attribute
{
public ValidRoleForAccess(UniversityRoles role)
{
Role = role;
}
public UniversityRoles Role { get; private set; }
}
/// <summary>
/// we suppose that just admins and masters can define new Lesson
/// </summary>
[ValidRoleForAccess(UniversityRoles.Admin)]
[ValidRoleForAccess(UniversityRoles.Master)]
public class Lesson
{
public Lesson(int id, string name, DateTime startTime, User owner)
{
var lessType = typeof(Lesson);
var validRolesForAccesses = lessType.GetCustomAttributes<ValidRoleForAccess>();
if (validRolesForAccesses.All(x => x.Role.ToString() != owner.GetType().Name))
{
throw new Exception("You are not Allowed to define a new lesson");
}
Id = id;
Name = name;
StartTime = startTime;
Owner = owner;
}
public int Id { get; private set; }
public string Name { get; private set; }
public DateTime StartTime { get; private set; }
/// <summary>
/// Owner is some one who define the lesson in university website
/// </summary>
public User Owner { get; private set; }
}
public abstract class User
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime DateOfBirth { get; set; }
}
public class Master : User
{
public DateTime HireDate { get; set; }
public Decimal Salary { get; set; }
public string Department { get; set; }
}
public class Student : User
{
public float GPA { get; set; }
}
class Program
{
static void Main(string[] args)
{
#region exampl1
var master = new Master()
{
Name = "Hamid Hasani",
Id = 1,
DateOfBirth = new DateTime(1994, 8, 15),
Department = "Computer Engineering",
HireDate = new DateTime(2018, 1, 1),
Salary = 10000
};
var math = new Lesson(1, "Math", DateTime.Today, master);
#endregion
#region exampl2
var student = new Student()
{
Name = "Hamid Hasani",
Id = 1,
DateOfBirth = new DateTime(1994, 8, 15),
GPA = 16
};
var literature = new Lesson(2, "literature", DateTime.Now.AddDays(7), student);
#endregion
ReadLine();
}
}
}
En el mundo real de la programación, tal vez no usemos este enfoque para usar atributos y lo dije por su punto educativo en el uso de atributos.