Eu tentei várias vezes, mas ainda não consigo entender o uso de atributos personalizados (já passei por muitos links).
Alguém pode me explicar um exemplo muito básico de um atributo personalizado com código?
Eu tentei várias vezes, mas ainda não consigo entender o uso de atributos personalizados (já passei por muitos links).
Alguém pode me explicar um exemplo muito básico de um atributo personalizado com código?
Respostas:
Embora o código para criar um atributo personalizado seja bastante simples, é muito importante que você entenda o que são os atributos:
Atributos são metadados compilados em seu programa. Os atributos em si não adicionam nenhuma funcionalidade a uma classe, propriedade ou módulo - apenas dados. No entanto, usando reflexão, pode-se aproveitar esses atributos para criar funcionalidade.
Então, por exemplo, vamos dar uma olhada no Bloco de Aplicativos de Validação , da Biblioteca Corporativa da Microsoft . Se você olhar um exemplo 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; }
Pelo trecho acima, pode-se supor que o código sempre será validado, sempre que alterado, de acordo com as regras do Validador (no exemplo, ter no mínimo 8 caracteres e no máximo 8 caracteres). Mas a verdade é que o Atributo não faz nada; conforme mencionado anteriormente, ele apenas adiciona metadados à propriedade.
Porém, a Biblioteca Corporativa possui um Validation.Validate
método que examinará seu objeto e, para cada propriedade, verificará se o conteúdo viola a regra informada pelo atributo.
Então, é assim que você deve pensar sobre atributos - uma forma de adicionar dados ao seu código que podem ser usados posteriormente por outros métodos / classes / etc.
Você começa escrevendo uma classe que deriva de Attribute :
public class MyCustomAttribute: Attribute
{
public string SomeProperty { get; set; }
}
Então você pode decorar qualquer coisa (classe, método, propriedade, ...) com este atributo:
[MyCustomAttribute(SomeProperty = "foo bar")]
public class Foo
{
}
e, finalmente, você usaria reflexão para buscá-lo:
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
}
Você pode limitar os tipos de destino aos quais este atributo personalizado pode ser aplicado usando o atributo AttributeUsage :
/// <summary>
/// This attribute can only be applied to classes
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class MyCustomAttribute : Attribute
Coisas importantes a saber sobre os atributos:
var value = typeof(Foo).GetCustomAttributes<MyCustomAttribute>().First().SomeProperty;
Utilizando / copiando a ótima resposta de Darin Dimitrov, veja como acessar um atributo personalizado em uma propriedade e não em uma classe:
A propriedade decorada [da classe Foo
]:
[MyCustomAttribute(SomeProperty = "This is a custom property")]
public string MyProperty { get; set; }
Buscando:
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;
}
Você pode lançar isso em um loop e usar reflexão para acessar este atributo personalizado em cada propriedade da classe Foo
, também:
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
}
}
Muito obrigado a você, Darin !!
object[] attribute = propertyInfo.GetCustomAttributes(typeof(???), true);
Eu só quero iterar sobre todos eles e chamar um método m1()
de cada atributo desconhecido
A resposta curta é para criar um atributo em c #, você só precisa herdá-lo da classe Attribute, apenas isto :)
Mas aqui vou explicar os atributos em detalhes:
basicamente atributos são classes que podemos usar para aplicar nossa lógica a assemblies, classes, métodos, propriedades, campos, ...
Em .Net, a Microsoft forneceu alguns atributos predefinidos como atributos obsoletos ou de validação como ([obrigatório], [StringLength (100)], [intervalo (0, 999,99)]), também temos tipos de atributos como ActionFilters em asp.net que pode ser muito útil para aplicar nossa lógica desejada aos nossos códigos (leia este artigo sobre filtros de ação se você for apaixonado por aprender)
um outro ponto, você pode aplicar um tipo de configuração em seu atributo via AttibuteUsage.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)]
Quando você decora uma classe de atributo com AttributeUsage, pode dizer ao compilador c # onde vou usar este atributo: vou usar isso em classes, em assemblies em propriedades ou em ... e meu atributo tem permissão para usar várias vezes em alvos definidos (classes, assemblies, propriedades, ...) ou não ?!
Após esta definição sobre os atributos, vou mostrar um exemplo: Imagine que queremos definir uma nova aula na universidade e queremos permitir que apenas administradores e mestres em nossa universidade definam uma nova aula, ok?
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();
}
}
}
No mundo real da programação, talvez não usemos essa abordagem para usar atributos e eu disse isso por causa de seu ponto educacional no uso de atributos