Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Атрибуты предоставляют способ связывания информации с кодом декларативным способом. Они также могут предоставлять многократно используемый элемент, который можно применять к различным целевым объектам. Рассмотрим ObsoleteAttribute. Его можно применять к классам, структурым, методам, конструкторам и т. д. Он объявляет , что элемент устарел. Задача компилятора C# заключается в том, чтобы найти этот атрибут и выполнить соответствующие действия в ответ.
В этом руководстве вы узнаете, как добавлять атрибуты в код, создавать и использовать собственные атрибуты, а также использовать некоторые атрибуты, встроенные в .NET.
Предпосылки
Необходимо настроить компьютер для запуска .NET. Инструкции по установке можно найти на странице загрузки .NET . Это приложение можно запустить в Windows, Ubuntu Linux, macOS или в контейнере Docker. Вам нужно установить любимый редактор кода. В следующих описаниях используется Visual Studio Code, который является кроссплатформенным редактором с открытым кодом. Однако вы можете использовать все инструменты, с которыми вы комфортно.
Создание приложения
Теперь, когда вы установили все средства, создайте консольное приложение .NET. Чтобы использовать генератор командной строки, выполните следующую команду в любимой оболочке:
dotnet new console
Эта команда создает минимальные файлы проекта .NET. Запустите dotnet restore
чтобы восстановить зависимости, необходимые для компиляции этого проекта.
Вам не нужно выполнять команду dotnet restore
, так как она выполняется неявно всеми командами, которые требуют восстановления, например dotnet new
, dotnet build
, dotnet run
, dotnet test
, dotnet publish
и dotnet pack
. Чтобы отключить неявное восстановление, используйте параметр --no-restore
.
Команду dotnet restore
по-прежнему удобно использовать в некоторых сценариях, где необходимо явное восстановление, например в сборках с использованием непрерывной интеграции в Azure DevOps Services или системах сборки, где требуется явно контролировать время восстановления.
В документации по dotnet restore
приведены сведения об управлении каналами NuGet.
Чтобы выполнить программу, используйте dotnet run
. Вы должны увидеть вывод "Hello, World" на консоль.
Добавление атрибутов в код
В C#атрибуты — это классы, наследуемые от Attribute
базового класса. Любой класс, наследующий от Attribute
, может использоваться как своего рода "тег" на других элементах кода. Например, есть атрибут, называемый ObsoleteAttribute
. Этот атрибут сигнализирует о том, что код устарел и больше не должен использоваться. Этот атрибут помещается в класс, например, с помощью квадратных скобок.
[Obsolete]
public class MyClass
{
}
Хотя класс называется ObsoleteAttribute
, в коде необходимо использовать только [Obsolete]
. Большинство кода C# следует этому соглашению. При выборе можно использовать полное имя [ObsoleteAttribute]
.
При маркировке устаревшего класса рекомендуется предоставить некоторые сведения о том, почему это устарело, и (или) что следует использовать. Для предоставления этого объяснения вы включаете строковый параметр в устаревший атрибут.
[Obsolete("ThisClass is obsolete. Use ThisClass2 instead.")]
public class ThisClass
{
}
Строка передается в качестве аргумента конструктору ObsoleteAttribute
, как если бы вы писали var attr = new ObsoleteAttribute("some string")
.
Параметры конструктора атрибутов ограничены простыми типами и литералами: bool, int, double, string, Type, enums, etc
и массивами этих типов.
Нельзя использовать выражение или переменную. Вы можете использовать позиционные или именованные параметры.
Создание собственного атрибута
Вы создаете атрибут, определяя новый класс, наследуемый от Attribute
базового класса.
public class MySpecialAttribute : Attribute
{
}
В приведенном выше коде можно использовать [MySpecial]
(или [MySpecialAttribute]
) в качестве атрибута в другом месте базы кода.
[MySpecial]
public class SomeOtherClass
{
}
Атрибуты в библиотеке базовых классов .NET, такие как ObsoleteAttribute
, вызывают определенные действия в компиляторе. Однако любой атрибут, создаваемый вами, действует только как метаданные и не приводит к выполнению кода в классе атрибутов. Вам решать, как использовать эти метаданные в другом месте кода.
Здесь есть подвох, будьте внимательны. Как упоминалось ранее, при использовании атрибутов можно передавать только определенные типы. Однако при создании типа атрибута компилятор C# не останавливает создание этих параметров. В следующем примере вы создали атрибут с конструктором, который компилируется правильно.
public class GotchaAttribute : Attribute
{
public GotchaAttribute(Foo myClass, string str)
{
}
}
Однако вы не можете использовать этот конструктор с синтаксисом атрибутов.
[Gotcha(new Foo(), "test")] // does not compile
public class AttributeFail
{
}
Предыдущий код вызывает ошибку компилятора, например Attribute constructor parameter 'myClass' has type 'Foo', which is not a valid attribute parameter type
Ограничение использования атрибутов
Атрибуты можно использовать в следующих "целевых объектах". Приведенные выше примеры показывают их на классах, но их также можно использовать для:
- Собрание
- Класс
- Конструктор
- Делегировать
- Перечисление
- Событие
- Поле
- Обобщенный параметр
- Интерфейс
- Метод
- Модуль
- Параметр
- Недвижимость
- ReturnValue
- Структура
При создании класса атрибутов по умолчанию C# позволяет использовать этот атрибут для любого из возможных целевых объектов атрибутов. Если вы хотите ограничить атрибут определенными целевыми объектами, это можно сделать с помощью AttributeUsageAttribute
класса атрибутов. Вот именно, атрибут на атрибуте!
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public class MyAttributeForClassAndStructOnly : Attribute
{
}
Если вы попытаетесь поместить приведенный выше атрибут на то, что не является классом или структурой, вы получите ошибку компилятора, например 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()
{ }
}
Использование атрибутов, присоединенных к элементу кода
Атрибуты действуют как метаданные. Без какой-либо внешней силы, они на самом деле ничего не делают.
Для поиска и работы с атрибутами требуется рефлексия. Отражение позволяет писать код в C#, который проверяет другой код. Например, можно использовать отражение для получения сведений о классе (добавьте using System.Reflection;
в голову кода):
TypeInfo typeInfo = typeof(MyClass).GetTypeInfo();
Console.WriteLine("The assembly qualified name of MyClass is " + typeInfo.AssemblyQualifiedName);
Это выводит что-то вроде: The assembly qualified name of MyClass is ConsoleApplication.MyClass, attributes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
После получения объекта TypeInfo
(или объекта MemberInfo
, FieldInfo
или другого объекта), можно использовать метод GetCustomAttributes
. Этот метод возвращает коллекцию Attribute
объектов. Вы также можете использовать GetCustomAttribute
и указать тип атрибута.
Вот пример применения GetCustomAttributes
на MemberInfo
для MyClass
(который мы видели ранее с атрибутом [Obsolete]
).
var attrs = typeInfo.GetCustomAttributes();
foreach(var attr in attrs)
Console.WriteLine("Attribute on MyClass: " + attr.GetType().Name);
Это выводится в консоль: Attribute on MyClass: ObsoleteAttribute
Попробуйте добавить другие атрибуты к MyClass
.
Важно отметить, что эти Attribute
объекты создаются лениво. То есть они не создаются, пока вы не используете GetCustomAttribute
или GetCustomAttributes
. Они также создаются каждый раз. Вызов GetCustomAttributes
дважды в строке возвращает два разных экземпляра ObsoleteAttribute
.
Общие атрибуты во время выполнения
Атрибуты используются многими инструментами и платформами. NUnit использует такие [Test]
атрибуты, как и [TestFixture]
используемые тестовой командой NUnit. ASP.NET MVC использует такие атрибуты, как [Authorize]
и предоставляет платформу фильтров действий для выполнения перекрестных задач по действиям MVC.
PostSharp использует синтаксис атрибута, чтобы разрешить программирование на основе аспектов в C#.
Ниже приведены несколько важных атрибутов, встроенных в библиотеки базовых классов .NET Core:
-
[Obsolete]
. Этот объект использовался в приведенных выше примерах, и он находится вSystem
пространстве имен. Полезно предоставить декларативную документацию по изменяющейся базе кода. Сообщение можно указать в виде строки, а другой логический параметр можно использовать для эскалации предупреждения компилятора до ошибки компилятора. -
[Conditional]
. Этот атрибут находится вSystem.Diagnostics
пространстве имен. Этот атрибут можно применять к методам (или классам атрибутов). Необходимо передать строку конструктору. Если эта строка не соответствует директиве#define
, компилятор C# удаляет вызовы этого метода (но не сам метод). Обычно этот метод используется для отладки (диагностики). -
[CallerMemberName]
. Этот атрибут можно использовать для параметров и является частью пространства именSystem.Runtime.CompilerServices
.CallerMemberName
— это атрибут, используемый для внедрения имени метода, вызывающего другой метод. Это способ исключить "волшебные строки" при реализации INotifyPropertyChanged в различных платформах пользовательского интерфейса. В качестве примера:
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
}
}
}
}
В приведенном выше коде не требуется иметь литеральную "Name"
строку. Использование CallerMemberName
предотвращает ошибки, связанные с опечатками, а также обеспечивает более плавное рефакторингом и переименование. Атрибуты приносят декларативную силу в C#, но они являются формой метаданных кода и не действуют сами по себе.