Atributos
Os atributos fornecem um método avançado de associação de metadados, ou informações declarativas, com código (assemblies, tipos, métodos, propriedades e assim por diante). Depois que um atributo é associado a uma entidade de programa, o atributo pode ser consultado em tempo de execução usando uma técnica chamada reflexão.
Os atributos têm as seguintes propriedades:
- Os atributos adicionam metadados ao seu programa. Metadado é informação sobre os tipos definidos em um programa. Todos os assemblies .NET contêm um conjunto de metadados especificado que descreve os tipos e os membros de tipo definidos no assembly. Você pode adicionar atributos personalizados para especificar qualquer informação adicional necessária.
- Você pode aplicar um ou mais atributos a assemblies inteiros, módulos ou elementos de programa menores, como classes e propriedades.
- Os atributos podem aceitar argumentos da mesma forma que métodos e propriedades.
- Seu programa pode examinar seus próprios metadados ou metadados em outros programas usando reflexão.
Reflection fornece objetos (do tipo Type) que descrevem assemblies, módulos e tipos. Você pode usar a reflexão para criar dinamicamente uma instância de um tipo, associar 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. Se você estiver usando atributos em seu código, a reflexão permitirá que você os acesse. Para obter mais informações, consulte Attributes.
Aqui está um exemplo simples de reflexão usando o método GetType() - herdado por todos os tipos da classe base Object
- para obter o tipo de uma variável:
Nota
Adicione using System;
e using System.Reflection;
na parte superior do arquivo .cs.
// Using GetType to obtain type information:
int i = 42;
Type type = i.GetType();
Console.WriteLine(type);
A saída é: System.Int32
.
O exemplo a seguir usa a reflexão para obter o nome completo do assembly carregado.
// Using Reflection to get information of an Assembly:
Assembly info = typeof(int).Assembly;
Console.WriteLine(info);
A saída será algo semelhante a: System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e
.
Nota
As palavras-chave C# protected
e internal
não têm nenhum significado em IL (Linguagem Intermediária) e não são usadas nas APIs de reflexão. Os termos correspondentes na IL são Família e Assembly. Para identificar um método internal
usando reflexão, use a propriedade IsAssembly. Para identificar um método protected internal
, use o IsFamilyOrAssembly.
Usando atributos
Os atributos podem ser colocados em quase qualquer declaração, embora um atributo específico possa restringir os tipos de declarações nas quais ele é válido. Em C#, especifique um atributo colocando o nome do atributo entre colchetes ([]
) acima da declaração da entidade à qual ela se aplica.
Neste exemplo, o atributo SerializableAttribute é usado para aplicar uma característica específica a uma classe:
[Serializable]
public class SampleClass
{
// Objects of this type can be serialized.
}
Um método com o atributo DllImportAttribute é declarado como o seguinte exemplo:
[System.Runtime.InteropServices.DllImport("user32.dll")]
extern static void SampleMethod();
Mais de um atributo pode ser colocado em uma declaração, como mostra o exemplo a seguir:
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. Um exemplo desse atributo multiuso é ConditionalAttribute:
[Conditional("DEBUG"), Conditional("TEST1")]
void TraceMethod()
{
// ...
}
Nota
Por convenção, todos os nomes de atributo terminam com a palavra "Atributo" para distingui-los de outros itens nas bibliotecas do .NET. No entanto, você não precisa especificar o sufixo de atributo ao usar atributos no código. Por exemplo, [DllImport]
é equivalente a [DllImportAttribute]
, mas DllImportAttribute
é o nome real do atributo na Biblioteca de Classes do .NET.
Parâmetros de atributo
Muitos atributos têm parâmetros, que podem ser posicionais, sem nome ou nomeados. Todos os parâmetros posicionais devem ser especificados em uma determinada ordem e não podem ser omitidos. Os parâmetros nomeados são opcionais e podem ser especificados em qualquer ordem. Os parâmetros posicionais são especificados primeiro. Por exemplo, esses três atributos são equivalentes:
[DllImport("user32.dll")]
[DllImport("user32.dll", SetLastError=false, ExactSpelling=false)]
[DllImport("user32.dll", ExactSpelling=false, SetLastError=false)]
O primeiro parâmetro, o nome DLL, é posicional e sempre vem primeiro; os outros são nomeados. Nesse caso, ambos os parâmetros nomeados têm valor padrão false, de modo que podem ser omitidos. Os parâmetros posicionais correspondem aos parâmetros do construtor de atributo. Parâmetros nomeados ou opcionais correspondem a propriedades ou campos do atributo. Consulte a documentação do atributo individual para obter informações sobre valores de parâmetro padrão.
Para obter mais informações sobre tipos de parâmetro permitidos, consulte a seção atributos da especificação da linguagem C# .
Destinos do atributo
O destino de um atributo é a entidade à qual o atributo se aplica. Por exemplo, um atributo pode se aplicar a uma classe, a um método específico ou a um assembly inteiro. Por padrão, um atributo se aplica ao elemento que o segue. Mas você também pode identificar explicitamente, por exemplo, se um atributo é aplicado a um método ou ao seu parâmetro ou ao seu valor retornado.
Para identificar explicitamente um destino de atributo, use a seguinte sintaxe:
[target : attribute-list]
A lista de possíveis valores de target
é mostrada na tabela a seguir.
Valor-alvo | Aplica-se a |
---|---|
assembly |
Montagem completa |
module |
Módulo de montagem atual |
field |
Campo em uma classe ou estrutura |
event |
Acontecimento |
method |
Método ou acessadores de propriedade get e set |
param |
Parâmetros de método ou parâmetros de acessador de propriedade set |
property |
Propriedade |
return |
Valor retornado de um método, indexador de propriedade ou acessador de propriedade get |
type |
Struct, classe, interface, enum ou delegado |
Você especificaria o valor de destino field
para aplicar um atributo ao campo de backup 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; }
Nota
Independentemente dos destinos nos quais ValidatedContract
é definido como válido, o destino return
deve ser especificado, mesmo que ValidatedContract
tenham sido definidos para aplicar apenas aos valores retornados. Em outras palavras, o compilador não usará as informações de AttributeUsage
para resolver alvos de atributos ambíguos. Para obter mais informações, consulte AttributeUsage.
Usos comuns para atributos
A lista a seguir inclui alguns dos usos comuns de atributos no código:
- Marcando métodos usando o atributo
WebMethod
nos serviços Web para indicar que o método deve ser chamado pelo protocolo SOAP. Para obter mais informações, consulte WebMethodAttribute. - Descrevendo como organizar os parâmetros de método ao interoperar com código nativo. Para obter mais informações, consulte MarshalAsAttribute.
- Descrevendo as propriedades COM para classes, métodos e interfaces.
- Chamando código não gerenciado usando a classe DllImportAttribute.
- Descrevendo seu conjunto de componentes em termos de título, versão, descrição ou marca registrada.
- Descrever quais membros de uma classe devem ser serializados para persistência.
- Descrever como fazer mapeamento entre nós XML e membros de classe para serialização de XML.
- Descrevendo os requisitos de segurança para métodos.
- Especificando características usadas para impor a segurança.
- Gerenciar as otimizações do compilador JIT (just-in-time) para que o código permaneça fácil de depurar.
- Obter informações sobre o chamador de um método.
Visão geral da reflexão
A reflexão é útil nas seguintes situações:
- Quando você precisa acessar atributos nos metadados do programa. Para obter mais informações, consulte Recuperando informações armazenadas em atributos.
- Para examinar e instanciar tipos em um assembly.
- Para compilar novos tipos em tempo de execução. Usar as classes em System.Reflection.Emit.
- Para executar a associação tardia, acessar métodos em tipos criados em tempo de execução. Consulte o artigo Carregando e usando tipos dinamicamente.
Seções relacionadas
Para obter mais informações: