Partilhar via


Atributos

Os atributos fornecem uma maneira poderosa de associar metadados, ou informações declarativas, ao código (assemblies, tipos, métodos, propriedades e assim por diante). Depois de associar um atributo a uma entidade de programa, você pode consultar o atributo em tempo de execução usando uma técnica chamada reflection.

Os atributos têm as seguintes propriedades:

  • Os atributos adicionam metadados ao seu programa. Metadados é a informação sobre os tipos definidos em um programa. Todos os assemblies .NET contêm um conjunto especificado de metadados que descrevem os tipos e membros de tipo definidos no assembly. Você pode adicionar atributos personalizados para especificar quaisquer outras informações necessárias.
  • Os atributos podem ser aplicados a assemblies inteiros, módulos ou elementos menores do programa, como classes e propriedades.
  • Os atributos podem aceitar argumentos da mesma forma que métodos e propriedades.
  • Os atributos permitem que um programa examine seus próprios metadados ou metadados em outros programas usando reflexão.

Trabalhar com reflexão

Reflection APIs fornecidas por Type descrevem assemblies, módulos e tipos. Você pode usar a reflexão para criar dinamicamente uma instância de um tipo, vincular o tipo a um objeto existente ou obter o tipo de um objeto existente e invocar seus métodos ou acessar seus campos e propriedades. Quando você usa atributos em seu código, a reflexão permite acessá-los. Para obter mais informações, consulte Atributos.

Aqui está um exemplo simples de reflexão com o método GetType(). Todos os tipos da classe base Object herdam esse método, que é usado para obter o tipo de uma variável:

Observação

Certifique-se de adicionar as instruções using System; e using System.Reflection; na parte superior do arquivo de código C# (.cs).

// Using GetType to obtain type information:
int i = 42;
Type type = i.GetType();
Console.WriteLine(type);

A saída mostra o tipo:

System.Int32

O exemplo a seguir usa reflection para obter o nome completo do assembly carregado.

// Using Reflection to get information of an Assembly:
Assembly info = typeof(int).Assembly;
Console.WriteLine(info);

O resultado é semelhante ao seguinte exemplo:

System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e

Diferenças de palavras-chave para IL

As palavras-chave C# protected e internal não têm significado na linguagem intermediária (IL) e não são usadas nas APIs de reflexão. Os termos correspondentes em IL são Family e Assembly. Aqui estão algumas maneiras de usar esses termos:

  • Para identificar um método internal usando reflexão, use a propriedade IsAssembly.
  • Para identificar um método protected internal, use o IsFamilyOrAssembly.

Trabalhar com atributos

Os atributos podem ser colocados em quase todas as declarações, embora um atributo específico possa restringir os tipos de declarações nas quais é válido. Em C#, você especifica um atributo colocando o nome do atributo entre colchetes ([]) acima da declaração da entidade à qual ele se aplica.

Neste exemplo, você usa o atributo SerializableAttribute para aplicar uma característica específica a uma classe:

[Serializable]
public class SampleClass
{
    // Objects of this type can be serialized.
}

Você pode declarar um método com o atributo DllImportAttribute:

[System.Runtime.InteropServices.DllImport("user32.dll")]
extern static void SampleMethod();

Você pode colocar vários atributos em uma declaração:

void MethodA([In][Out] ref double x) { }
void MethodB([Out][In] ref double x) { }
void MethodC([In, Out] ref double x) { }

Alguns atributos podem ser especificados mais de uma vez para uma determinada entidade. O exemplo a seguir mostra multiuso do atributo ConditionalAttribute:

[Conditional("DEBUG"), Conditional("TEST1")]
void TraceMethod()
{
    // ...
}

Observação

Por convenção, todos os nomes de atributos terminam com o sufixo "Atributo" para distingui-los de outros tipos nas bibliotecas .NET. No entanto, você não precisa especificar o sufixo de atributo quando você usa atributos no código. Por exemplo, uma declaração [DllImport] é equivalente a uma declaração [DllImportAttribute], mas DllImportAttribute é o nome real da classe na Biblioteca de Classes do .NET.

Parâmetros de atributo

Muitos atributos têm parâmetros, que podem ser posicional, sem nome ou nomeado. A tabela a seguir descreve como trabalhar com atributos nomeados e posicionais:

Parâmetros posicionais

Parâmetros do construtor de atributo:

Parâmetros nomeados

Propriedades ou campos do atributo:

  • Deve especificar, não pode omitir
  • Especifique sempre primeiro
  • Especificar em uma determinada ordem
  • Sempre opcional, omitir quando falso
  • Especifique após os parâmetros posicionais
  • Especificar em qualquer ordem

Por exemplo, o código a seguir mostra três atributos DllImport equivalentes:

[DllImport("user32.dll")]
[DllImport("user32.dll", SetLastError=false, ExactSpelling=false)]
[DllImport("user32.dll", ExactSpelling=false, SetLastError=false)]

O primeiro parâmetro, o nome da DLL, é posicional e sempre vem em primeiro lugar. As outras instâncias são nomeadas parâmetros. Nesse cenário, ambos os parâmetros nomeados têm padrão como false, pelo que podem ser omitidos. Consulte a documentação do atributo individual para obter informações sobre valores de parâmetros padrão. Para obter mais informações sobre os tipos de parâmetros permitidos, consulte a seção Atributos da especificação da linguagem C# .

Destinos de atributos

O destino do de um atributo é a entidade à qual o atributo se aplica. Por exemplo, um atributo pode ser aplicado a uma classe, um método ou um assembly. Por padrão, um atributo se aplica ao elemento que o segue. Mas você também pode identificar explicitamente o elemento a ser associado, como um método, um parâmetro ou o valor de retorno.

Para identificar explicitamente um destino de atributo, use a seguinte sintaxe:

[target : attribute-list]

A tabela a seguir mostra a lista de possíveis valores de target.

Valor alvo Aplica-se a
assembly Montagem completa
module Módulo de montagem atual
field Campo em uma classe ou uma estrutura
event Evento
method Método ou acessores de propriedade get e set
param Parâmetros do método ou parâmetros do acessor de propriedade set
property Propriedade
return Valor de retorno de um método, indexador de propriedade, ou acessor de propriedade get
type Estrutura, classe, interface, enumeração ou delegado

Você pode especificar o valor de destino field para aplicar um atributo ao campo de suporte criado para uma propriedade implementada automaticamente.

O exemplo a seguir mostra como aplicar atributos a assemblies e módulos. Para obter mais informações, consulte Atributos comuns (C#).

using System;
using System.Reflection;
[assembly: AssemblyTitleAttribute("Production assembly 4")]
[module: CLSCompliant(true)]

O exemplo a seguir mostra como aplicar atributos a métodos, parâmetros de método e valores de retorno de método em C#.

// default: applies to method
[ValidatedContract]
int Method1() { return 0; }

// applies to method
[method: ValidatedContract]
int Method2() { return 0; }

// applies to parameter
int Method3([ValidatedContract] string contract) { return 0; }

// applies to return value
[return: ValidatedContract]
int Method4() { return 0; }

Observação

Independentemente dos destinos nos quais o atributo ValidatedContract é definido como válido, o destino return deve ser especificado, mesmo que o atributo ValidatedContract seja definido para se aplicar apenas aos valores de retorno. Em outras palavras, o compilador não usa as informações AttributeUsage para resolver alvos de atributos ambíguos. Para obter mais informações, consulte AttributeUsage.

Rever formas de utilizar atributos

Aqui estão algumas maneiras comuns de usar atributos no código:

  • Marque os métodos do controlador que respondem a mensagens POST usando o atributo HttpPost. Para obter mais informações, consulte a classe HttpPostAttribute.
  • Descreva como organizar parâmetros do método ao interoperar com código nativo. Para obter mais informações, consulte a classe MarshalAsAttribute.
  • Descreva as propriedades COM (Component Object Model) para classes, métodos e interfaces.
  • Chame o código não gerenciado usando a classe DllImportAttribute.
  • Descreva sua montagem em termos de título, versão, descrição ou marca registrada.
  • Descreva quais membros de uma classe devem ser serializados para persistência.
  • Descreva como mapear entre membros de classe e nós XML para serialização XML.
  • Descreva os requisitos de segurança para métodos.
  • Especifique as características usadas para impor a segurança.
  • Controle otimizações com o compilador just-in-time (JIT) para que o código permaneça fácil de depurar.
  • Obtenha informações sobre o chamador para um método.

Rever cenários de reflexão

A reflexão é útil nos seguintes cenários: