Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Os atributos fornecem uma maneira de associar informações ao código de forma declarativa. Eles também podem fornecer um elemento reutilizável que pode ser aplicado a vários destinos. Considere o ObsoleteAttribute. Ele pode ser aplicado a classes, structs, métodos, construtores e muito mais. Ele declara que o elemento é obsoleto. Em seguida, cabe ao compilador C# procurar esse atributo e executar alguma ação em resposta.
Neste tutorial, você aprenderá a adicionar atributos ao seu código, como criar e usar seus próprios atributos e como usar alguns atributos integrados ao .NET.
Pré-requisitos
Você precisa configurar seu computador para executar o .NET. Você pode encontrar as instruções de instalação na página Downloads do .NET . Você pode executar esse aplicativo no Windows, Ubuntu Linux, macOS ou em um contêiner do Docker. Você precisa instalar seu editor de código favorito. As descrições a seguir usam o Visual Studio Code, que é um editor multiplataforma de software livre. No entanto, você pode usar as ferramentas com as quais se sente confortável.
Criar o aplicativo
Agora que você instalou todas as ferramentas, crie um novo aplicativo de console do .NET. Para usar o gerador de linha de comando, execute o seguinte comando no shell favorito:
dotnet new console
Esse comando cria arquivos de projeto .NET básicos. Você executa dotnet restore
para restaurar as dependências necessárias para compilar este projeto.
Não é necessário executar dotnet restore
, pois ele é executado implicitamente por todos os comandos que exigem uma restauração, como dotnet new
, dotnet build
, dotnet run
, dotnet test
, dotnet publish
e dotnet pack
. Para desabilitar a restauração implícita, use a opção --no-restore
.
O comando dotnet restore
ainda é útil em determinados cenários em que realizar uma restauração explícita faz sentido, como compilações de integração contínua no Azure DevOps Services ou em sistemas de compilação que precisam controlar explicitamente quando a restauração ocorrerá.
Para obter informações sobre como gerenciar feeds do NuGet, confira a documentação do dotnet restore
.
Para executar o programa, use dotnet run
. Você deve ver a saída do "Olá, Mundo" no console.
Adicionar atributos ao código
Em C#, os atributos são classes que herdam da Attribute
classe base. Qualquer classe que herda de Attribute
pode ser usada como uma espécie de "marca" em outras partes do código. Por exemplo, há um atributo chamado ObsoleteAttribute
. Esse atributo sinaliza que o código está obsoleto e não deve mais ser usado. Você coloca esse atributo em uma classe, por exemplo, usando colchetes.
[Obsolete]
public class MyClass
{
}
Embora a classe seja chamada ObsoleteAttribute
, é necessário usar [Obsolete]
apenas no código. A maioria dos códigos C# segue esta convenção. Você pode usar o nome [ObsoleteAttribute]
completo se quiser.
Ao marcar uma classe obsoleta, é uma boa ideia fornecer algumas informações sobre por que ela é obsoleta e/ou o que usar em vez disso. Você inclui um parâmetro de cadeia de caracteres para o atributo Obsoleto para fornecer essa explicação.
[Obsolete("ThisClass is obsolete. Use ThisClass2 instead.")]
public class ThisClass
{
}
A cadeia de caracteres está sendo passada como um argumento para um ObsoleteAttribute
construtor, como se você estivesse escrevendo var attr = new ObsoleteAttribute("some string")
.
Os parâmetros para um construtor de atributo são limitados a tipos/literais simples: bool, int, double, string, Type, enums, etc
e matrizes desses tipos.
Você não pode usar uma expressão ou uma variável. Você é livre para usar parâmetros posicionais ou nomeados.
Criar seu próprio atributo
Você cria um atributo definindo uma nova classe que herda da Attribute
classe base.
public class MySpecialAttribute : Attribute
{
}
Com o código anterior, você pode usar [MySpecial]
(ou [MySpecialAttribute]
) como um atributo em outro lugar na base de código.
[MySpecial]
public class SomeOtherClass
{
}
Atributos na biblioteca de classes base do .NET, como ObsoleteAttribute
, disparam determinados comportamentos dentro do compilador. No entanto, qualquer atributo criado atua apenas como metadados e não resulta na execução de nenhum código dentro da classe de atributo. Cabe a você agir sobre esses metadados em outro lugar em seu código.
Há uma pegadinha aqui. Conforme mencionado anteriormente, somente determinados tipos podem ser passados como argumentos ao usar atributos. No entanto, ao criar um tipo de atributo, o compilador C# não impede que você crie esses parâmetros. No exemplo a seguir, você criou um atributo com um construtor que é compilado corretamente.
public class GotchaAttribute : Attribute
{
public GotchaAttribute(Foo myClass, string str)
{
}
}
No entanto, não é possível usar esse construtor com sintaxe de atributo.
[Gotcha(new Foo(), "test")] // does not compile
public class AttributeFail
{
}
O código anterior causa um erro de compilador como Attribute constructor parameter 'myClass' has type 'Foo', which is not a valid attribute parameter type
Como restringir o uso de atributos
Os atributos podem ser usados nos seguintes "destinos". Os exemplos anteriores os mostram em classes, mas também podem ser usados em:
- Assembléia
- Classe
- Construtor
- Delegar
- Enumeração
- Acontecimento
- Campo
- GenericParameter
- Interfase
- Método
- Módulo
- Parâmetro
- Propriedade
- ReturnValue
- Estrutura
Quando você cria uma classe de atributo, por padrão, o C# permite que você use esse atributo em qualquer um dos possíveis destinos de atributo. Se você quiser restringir seu atributo a determinados destinos, poderá fazer isso usando a AttributeUsageAttribute
classe de atributo. Isso mesmo, um atributo em cima de um atributo!
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public class MyAttributeForClassAndStructOnly : Attribute
{
}
Se você tentar colocar o atributo acima em algo que não seja uma classe ou um struct, você receberá um erro do compilador como Attribute 'MyAttributeForClassAndStructOnly' is not valid on this declaration type. It is only valid on 'class, struct' declarations
public class Foo
{
// if the below attribute was uncommented, it would cause a compiler error
// [MyAttributeForClassAndStructOnly]
public Foo()
{ }
}
Como usar atributos anexados a um elemento de código
Os atributos atuam como metadados. Sem alguma força externa, eles não fazem nada.
Para localizar e agir sobre atributos, a reflexão é necessária. A reflexão permite que você escreva código em C# que examine outro código. Por exemplo, você pode usar Reflexão para obter informações sobre uma classe (adicionar using System.Reflection;
à cabeça do código):
TypeInfo typeInfo = typeof(MyClass).GetTypeInfo();
Console.WriteLine("The assembly qualified name of MyClass is " + typeInfo.AssemblyQualifiedName);
Isso imprime algo como: The assembly qualified name of MyClass is ConsoleApplication.MyClass, attributes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Depois de ter um TypeInfo
objeto (ou um MemberInfo
, FieldInfo
ou outro objeto), você poderá usar o GetCustomAttributes
método. Esse método retorna uma coleção de Attribute
objetos. Você também pode usar GetCustomAttribute
e especificar um tipo de atributo.
Aqui está um exemplo de uso de GetCustomAttributes
em uma instância MemberInfo
de MyClass
(que vimos anteriormente, tem um atributo [Obsolete]
nele).
var attrs = typeInfo.GetCustomAttributes();
foreach(var attr in attrs)
Console.WriteLine("Attribute on MyClass: " + attr.GetType().Name);
Isso imprime no console: Attribute on MyClass: ObsoleteAttribute
. Tente adicionar outros atributos a MyClass
.
É importante observar que esses Attribute
objetos são instanciados de forma preguiçosa. Ou seja, eles não serão instanciados até que você use GetCustomAttribute
ou GetCustomAttributes
. Eles também são instanciados a cada vez. Chamar GetCustomAttributes
duas vezes em uma linha retorna duas instâncias diferentes de ObsoleteAttribute
.
Atributos comuns em tempo de execução
Os atributos são usados por muitas ferramentas e estruturas. O NUnit usa atributos como [Test]
e [TestFixture]
que são usados pelo executor de teste NUnit. ASP.NET MVC usa atributos como [Authorize]
e fornece um framework de filtros de ação para lidar com aspectos transversais nas ações do MVC.
O PostSharp usa a sintaxe de atributo para permitir programação orientada a aspectos em C#.
Aqui estão alguns atributos notáveis integrados às bibliotecas de classes base do .NET Core:
-
[Obsolete]
. Este foi usado nos exemplos acima e reside noSystem
namespace. É útil fornecer documentação declarativa sobre uma alteração da base de código. Uma mensagem pode ser fornecida na forma de uma cadeia de caracteres e outro parâmetro booliano pode ser usado para escalonar de um aviso do compilador para um erro do compilador. -
[Conditional]
. Esse atributo está noSystem.Diagnostics
namespace. Esse atributo pode ser aplicado a métodos (ou classes de atributo). Você deve passar uma cadeia de caracteres para o construtor. Se essa cadeia de caracteres não corresponder a uma#define
diretiva, o compilador C# removerá todas as chamadas para esse método (mas não o método em si). Normalmente, você usa essa técnica para fins de depuração (diagnóstico). -
[CallerMemberName]
. Esse atributo pode ser usado em parâmetros e reside noSystem.Runtime.CompilerServices
namespace.CallerMemberName
é um atributo usado para injetar o nome do método que está chamando outro método. É uma forma de eliminar 'cadeias de caracteres mágicas' ao implementar INotifyPropertyChanged em diversas estruturas de interface do usuário. Como exemplo:
public class MyUIClass : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
public void RaisePropertyChanged([CallerMemberName] string propertyName = default!)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private string? _name;
public string? Name
{
get { return _name;}
set
{
if (value != _name)
{
_name = value;
RaisePropertyChanged(); // notice that "Name" is not needed here explicitly
}
}
}
}
No código acima, você não precisa ter uma cadeia de caracteres literal "Name"
. Usar CallerMemberName
evita erros relacionados à digitação e também possibilita a refatoração/renomeação mais suave. Os atributos trazem poder declarativo para C#, mas são uma forma de código de metadados e não agem sozinhos.