Поделиться через


Атрибуты

Атрибуты предоставляют эффективный способ связывания метаданных или декларативной информации с кодом (сборки, типы, методы, свойства и т. д.). После связывания атрибута с сущностью программы можно запросить атрибут во время выполнения с помощью метода, называемого отражением.

Атрибуты имеют следующие свойства:

  • Атрибуты добавляют метаданные в программу. метаданные — это сведения о типах, определенных в программе. Все сборки .NET содержат указанный набор метаданных, описывающий типы и члены типов, определенные в сборке. Вы можете добавить настраиваемые атрибуты, чтобы указать любые другие необходимые сведения.
  • Атрибуты можно применять ко всем сборкам, модулям или небольшим элементам программы, таким как классы и свойства.
  • Атрибуты могут принимать аргументы так же, как методы и свойства.
  • Атрибуты позволяют программе проверять собственные метаданные или метаданные в других программах с помощью отражения.

Работа с отражением

API отражения, предоставляемые Type, описывают сборки, модули и типы. Можно использовать отражение для динамического создания экземпляра типа, привязки типа к существующему объекту или получения типа из существующего объекта и вызова методов или доступа к его полям и свойствам. При использовании атрибутов в коде отражение позволяет получить к ним доступ. Дополнительные сведения см. в разделе Атрибуты.

Вот простой пример использования метода GetType() для отражения. Все типы из Object базового класса наследуют этот метод, который используется для получения типа переменной:

Заметка

Убедитесь, что вы добавили операторы using System; и using System.Reflection; в верхней части файла кода C# (.cs).

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

Выходные данные показывают тип:

System.Int32

В следующем примере используется отражение для получения полного имени загруженной сборки.

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

Результат аналогичен следующему примеру:

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

Различия ключевых слов для IL

Ключевые слова protected C# и internal не имеют значения в промежуточном языке (IL) и не используются в API отражения. Соответствующие термины в IL — это семейства и сборки. Ниже приведены некоторые способы использования следующих терминов:

  • Чтобы определить internal метод с помощью отражения, используйте IsAssembly свойство.
  • Чтобы определить метод protected internal, используйте IsFamilyOrAssembly.

Работа с атрибутами

Атрибуты можно поместить почти в любое объявление, хотя определенный атрибут может ограничить типы объявлений, для которых он действителен. В C#можно указать атрибут, поместив имя атрибута, заключенного в квадратные скобки ([]) над объявлением сущности, к которой она применяется.

В этом примере вы используете атрибут SerializableAttribute, чтобы применить определенную характеристику к классу:

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

Можно объявить метод с атрибутом DllImportAttribute :

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

В объявлении можно поместить несколько атрибутов:

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

Некоторые атрибуты можно указать несколько раз для определенной сущности. В следующем примере показано многопользовательское использование атрибута ConditionalAttribute :

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

Заметка

По соглашению все имена атрибутов заканчиваются суффиксом "Атрибут", чтобы отличить их от других типов в библиотеках .NET. Однако при использовании атрибутов в коде не требуется указывать суффикс атрибутов. Например, [DllImport] объявление эквивалентно [DllImportAttribute] объявлению, но DllImportAttribute является фактическим именем класса в библиотеке классов .NET.

Параметры атрибута

Многие атрибуты имеют параметры, которые могут быть позициональными, неназванными или именованными. В следующей таблице описывается, как работать с именованными и позиционных атрибутами:

Позиционные параметры

Параметры конструктора атрибутов:

Именованные параметры

Свойства или поля атрибута:

  • Необходимо указать, нельзя пропустить
  • Всегда указывайте первое
  • Укажите в определенном порядке
  • Всегда необязательный, опущен при значении false
  • Укажите после позиционных параметров
  • Укажите в любом порядке

Например, в следующем коде показаны три эквивалентных DllImport атрибута:

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

Первый параметр, имя библиотеки DLL, является позиционным и всегда идет первым. Другие случаи — это именованные параметры. В этом сценарии оба именованных параметра по умолчанию используют значение false, поэтому они могут быть опущены. Сведения о значениях параметров по умолчанию см. в документации по отдельным атрибутам. Дополнительные сведения о разрешенных типах параметров см. в разделе Атрибуты спецификации языка C#.

Цели атрибутов

целевой атрибута — это сущность, к которой применяется атрибут. Например, атрибут может применяться к классу, методу или сборке. По умолчанию атрибут применяется к элементу, который следует за ним. Но вы также можете явно определить элемент для связывания, например метод, параметр или возвращаемое значение.

Чтобы явно определить целевой объект атрибута, используйте следующий синтаксис:

[target : attribute-list]

В следующей таблице показан список возможных target значений.

Целевое значение Применимо к
assembly Вся сборка
module Текущий модуль сборки
field Поле в классе или структуре
event Событие
method Метод или методы доступа к свойствам get и set
param Параметры метода или параметры аксессоров свойств set
property Свойство
return Возвращаемое значение метода, индексатора свойств или метода доступа к свойствам get
type Структура, класс, интерфейс, перечисление или делегат

Целевое field значение можно указать для применения атрибута к резервному полю, созданному для автоматически реализованного свойства.

В следующем примере показано, как применять атрибуты к сборкам и модулям. Дополнительные сведения см. в разделе "Общие атрибуты" (C#).

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

В следующем примере показано, как применять атрибуты к методам, параметрам метода и возвращаемым значениям метода в 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; }

Заметка

Независимо от целевых объектов, для которых атрибут ValidatedContract считается допустимым, целевой объект return должен быть указан, даже если атрибут ValidatedContract определен только для применения к возвращаемым значениям. Другими словами, компилятор не использует AttributeUsage сведения для разрешения неоднозначных целевых объектов атрибутов. Дополнительные сведения см. в разделе AttributeUsage.

Просмотр способов использования атрибутов

Ниже приведены некоторые распространенные способы использования атрибутов в коде:

  • Пометьте методы контроллера, которые отвечают на сообщения POST с помощью атрибута HttpPost . Дополнительные сведения см. в HttpPostAttribute классе.
  • Описание способов маршалирования параметров метода при взаимодействии с машинным кодом. Дополнительные сведения см. в MarshalAsAttribute классе.
  • Описание свойств объектной модели компонента (COM) для классов, методов и интерфейсов.
  • Вызов неуправляемого кода с помощью DllImportAttribute класса.
  • Опишите сборку с точки зрения названия, версии, описания или торговой марки.
  • Определите, какие элементы класса следует сериализовать для обеспечения сохранности данных.
  • Опишите, как сопоставить члены класса и узлы XML для сериализации XML.
  • Описание требований безопасности для методов.
  • Укажите характеристики, используемые для обеспечения безопасности.
  • Управляйте оптимизациями с помощью JIT-компилятора, чтобы код оставался легким для отладки.
  • Получение сведений о вызывающем методе.

Просмотр сценариев отражения

Отражение полезно в следующих сценариях: