C# - Atributos mais usados


  Hoje vou apresentar os atributos mais usados no C#.

Os atributos em C# fornecem uma maneira de adicionar metadados, comportamento ou configuração a vários elementos do programa.  A seguir vou apresentar os atributos mais usados.

Os atributos têm várias finalidades, incluindo:

  1. Metadados para ferramentas: Eles podem ser usados por ferramentas de desenvolvimento, como IDEs e compiladores, para ajudar a gerar código ou realizar análises estáticas.
  2. Controle de serialização: Alguns atributos, como [Serializable], indicam como os objetos de uma classe devem ser serializados para armazenamento ou transmissão.
  3. Mapeamento para bancos de dados: Atributos podem ser usados para mapear classes e propriedades para tabelas e colunas de bancos de dados em ORMs (Object-Relational Mapping).
  4. Segurança: Atributos podem ser usados para impor políticas de segurança, como exigir autenticação ou autorização para acessar um método ou recurso.
  5. Documentação e geração de código: Alguns atributos podem ser usados para fornecer documentação adicional ou personalizar a geração de código.

Os atributos são parte importante do sistema de reflexão do C# e podem ser acessados em tempo de execução para inspecionar informações sobre o código. Você também pode criar seus próprios atributos personalizados para estender o comportamento de seus tipos e membros de classe de acordo com as necessidades do seu projeto.

Para criar atributos personalizados, você deve criar uma classe que herda de System.. Essas classes devem ser marcadas com o sufixo "" por convenção.

Por exemplo:

[Usage(Targets.Class | Targets.Method)]
public class MeuAtributoPersonalizado : 
{
    // Defina propriedades e lógica personalizada aqui
}

A seguir vou apresentar os 25 atributos mais usados na linguagem C# :

1. [Obsolete]

Marca um elemento do programa como obsoleto ou depreciado, gerando um aviso ou erro quando usado.

[Obsolete("Este método esta depreciado, use MetodoNovo.")]
public void MetodoAntigo() { }

2. [Serializable]

Indica que um objeto pode ser serializado para armazenamento ou transmissão.

[Serializable]
public class SerializableObject { }

3. [DataContract] e [DataMember]

[DataContract]
public class ClienteWCF
{
   [DataMember(Name = "ID")] // Customiza o nome no contrato
   public int Id { get; set; }

   [DataMember(IsRequired = true)]
   public string Nome { get; set; }
}

Usado no Windows Communication Foundation (WCF) para especificar classes e membros serializáveis.

4. [DllImport]

class NativeMethods
{
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern int MessageBox(IntPtr hWnd, string text, string caption, uint type);
}

Usado para chamar funções de código não gerenciado.

5. [Conditional]

class DebugLogger
{
    [Conditional("DEBUG")]
    public static void Log(string message) => Console.WriteLine($"[DEBUG] {message}");
}

Especifica que um método deve ser chamado condicionalmente com base em símbolos de compilação.

6. [ThreadStatic]

[Serializable]
public class ThreadSafeData
{
    [ThreadStatic]
    public static int ThreadLocalValue;

    [NonSerialized]  // 12. Não serializa este campo
    public string TempData;
}

Declara o armazenamento local de thread para um campo, fornecendo a cada thread sua própria cópia.

7. [Serializable]

[Serializable]
public class ThreadSafeData
{
    [ThreadStatic]
    public static int ThreadLocalValue;

    [NonSerialized]  // 12. Não serializa este campo
    public string TempData;
}

Marca uma classe como serializável para serialização binária.

8. [DefaultValue]

public class Configuracao
{
    [DefaultValue(100)]
    public int Limite { get; set; } = 100;
}

Especifica o valor padrão para uma propriedade ou campo.

9. [Description]

public class Configuracao
{
    [Description("Nome completo do usuário")]
    public string UserName { get; set; }
}

Fornece uma descrição para uma propriedade, evento ou componente.

10. [DisplayName]

public class Configuracao
{
    [Description("Nome completo do usuário")]
    [DisplayName("Usuário")]
    public string UserName { get; set; }
}

Especifica um nome de exibição para uma propriedade ou evento.

11. [Browsable]

public class Configuracao
{
    [Description("Nome completo do usuário")]
    [DisplayName("Usuário")]
    [Browsable(false)]  // Oculta no designer
    public string UserName { get; set; }
}

Indica se uma propriedade ou evento deve ser exibido em um designer.

12. [NonSerialized]

[Serializable]
public class ThreadSafeData
{
    [NonSerialized]  // 12. Não serializa este campo
    public string TempData;
}

Impede que um campo seja serializado.

13. [XmlIgnore]

public class PedidoXML
{
    [XmlIgnore]
    public Guid InternalId { get; } = Guid.NewGuid();
}

Exclui uma propriedade da serialização XML.

14. [XmlElement]

public class PedidoXML
{
    [XmlElement("Item")]
    public string Produto { get; set; }
}

Especifica que uma propriedade deve ser serializada como um elemento XML.

15. [Authorize]

[Authorize(Roles = "Admin")]
[ApiController]
public class ProdutosController : ControllerBase
{
    [HttpGet]
    public IActionResult Get(int id) => Ok(new { Id = id });
}

Restringe o acesso a um controlador ou método de ação a usuários autorizados.

16. [Route]

[Authorize(Roles = "Admin")]  // 16. Restrição de acesso
[ApiController]
public class ProdutosController : ControllerBase
{
    [HttpGet]
    [Route("api/produtos/{id}")]  // 17. Rota customizada
    public IActionResult Get(int id) => Ok(new { Id = id });
}

Especifica o modelo de rota para um método de ação no ASP.NET Core.

17. [Required]

public class UsuarioModel
{
    [Required(ErrorMessage = "Email é obrigatório")]  // 18.
    [EmailAddress]
    public string Email { get; set; }

    [MinLength(6)]  // 20.
    [RegularExpression(@"^(?=.*[A-Za-z])(?=.*\d).+$", 
        ErrorMessage = "Senha deve conter letras e números")]  // 21.
    public string Senha { get; set; }
}

Indica que uma propriedade é necessária para validação do modelo.

18. [MaxLength]

public class UsuarioModel
{
    [Required(ErrorMessage = "Email é obrigatório")
    [EmailAddress]
    [MaxLength(100)]
    public string Email { get; set; }
}

Especifica o comprimento máximo de uma propriedade de cadeia de caracteres.

19. [MinLength]

public class UsuarioModel
{
    [MinLength(6)]
    public string Senha { get; set; }
}

Especifica o comprimento mínimo para uma propriedade de cadeia de caracteres.

20. [RegularExpression]

public class UsuarioModel
{
    [RegularExpression(@"^(?=.*[A-Za-z])(?=.*\d).+$",
        ErrorMessage = "Senha deve conter letras e números")
]  // 21.
    public string Senha { get; set; }
}

Define um padrão de expressão regular para validação de string.

21. [Key]

public class Pedido
{
    [Key]  // Chave primária
    public int PedidoId { get; set; }
}

Especifica uma chave primária para uma entidade no Entity Framework.

22. [ForeignKey]

public class Pedido
{
   [ForeignKey("Cliente")]  //Chave estrangeira
    public int ClienteId { get; set; }
}

Indica um relacionamento de chave estrangeira no Entity Framework.

23. [JsonProperty]

public class Produto
{
    [JsonPropertyName("product_id")]  //Nome customizado no JSON
    public int Id { get; set; }
}

Mapeia uma propriedade para um nome de propriedade JSON específico durante a serialização e desserialização.

24. [JsonIgnore]

public class Produto
{
    [JsonIgnore]  //Ignora na serialização
    public string CodigoInterno { get; set; }
}

Exclui uma propriedade da serialização JSON.

Potencializando seu Código com Atributos

Desta forma, os atributos em C# são ferramentas poderosas que elevam seu código a outro patamar de funcionalidade e organização. Como vimos, eles servem como:

- Facilitadores de desenvolvimento (com [Obsolete], [Conditional])
- Gerenciadores de dados (com [Serializable], [DataContract])
- Controladores de comportamento (com [Authorize], [Route])
- Organizadores de estrutura (com [Key], [ForeignKey])

O verdadeiro poder dos atributos está na capacidade de:

- Documentar seu código de forma estruturada
- Adicionar comportamentos sem alterar lógica principal
- Integrar-se perfeitamente com frameworks modernos

Comece aplicando os atributos nativos mais relevantes para seu projeto atual e, quando dominá-los, explore a criação de atributos customizados para soluções específicas.

Lembre-se: um uso bem dosado de atributos pode ser a diferença entre um código funcional e um código profissional, bem estruturado e pronto para escalar.

Que tal escolher 2 ou 3 atributos desta lista e aplicá-los em seu projeto atual ? O ganho em clareza e manutenibilidade pode ser imediato!

E estamos conversados...

"E Jesus, respondendo, disse-lhes: Ide, e anunciai a João as coisas que ouvis e vedes:
Os cegos veem, e os coxos andam; os leprosos são limpos, e os surdos ouvem; os mortos são ressuscitados, e aos pobres é anunciado o evangelho. "
Mateus 11:4,5

Referências:


José Carlos Macoratti