Что такое атрибуты в .NET?

Что такое атрибуты в .NET, для чего они нужны и как создавать собственные атрибуты?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
208
0
66 198
11
Перейти к ответу Данный вопрос помечен как решенный

Ответы 11

Атрибут - это класс, который содержит некоторые функции, которые вы можете применить к объектам в вашем коде. Чтобы создать его, создайте класс, наследующий от System.Attribute.

Что касается того, для чего они годны ... их применение практически безгранично.

http://www.codeproject.com/KB/cs/dotnetattributes.aspx

«функциональность» - здесь неправильное слово; это метаданные, а не функциональность

Marc Gravell 04.12.2014 11:19

Атрибуты подобны метаданным, применяемым к классам, методам или сборкам.

Они хороши для любого количества вещей (визуализация отладчика, маркировка вещей как устаревших, маркировка вещей как сериализуемых, список бесконечен).

Создать свои собственные - это просто, как пирог. Начни здесь:

http://msdn.microsoft.com/en-us/library/sw480ze8(VS.71).aspx

Вы можете использовать настраиваемые атрибуты как простой способ определения значений тегов в подклассах без необходимости многократно писать один и тот же код для каждого подкласса. Я наткнулся на хороший краткий пример Джона Уотерса о том, как определять и использовать настраиваемые атрибуты в вашем собственном коде.

На http://msdn.microsoft.com/en-us/library/aa288454(VS.71).aspx есть учебник

Ответ принят как подходящий

Метаданные. Данные о ваших объектах / методах / свойствах.

Например, я мог бы объявить атрибут с именем: DisplayOrder, чтобы я мог легко контролировать, в каком порядке свойства должны отображаться в пользовательском интерфейсе. Затем я мог бы добавить его в класс и написать некоторые компоненты графического интерфейса, которые извлекают атрибуты и соответствующим образом упорядочивают элементы пользовательского интерфейса.

public class DisplayWrapper
{
    private UnderlyingClass underlyingObject;

    public DisplayWrapper(UnderlyingClass u)
    {
        underlyingObject = u;
    }

    [DisplayOrder(1)]
    public int SomeInt
    {
        get
        {
            return underlyingObject .SomeInt;
        }
    }

    [DisplayOrder(2)]
    public DateTime SomeDate
    {
        get
        {
            return underlyingObject .SomeDate;
        }
    }
}

Тем самым гарантируя, что SomeInt всегда отображается перед SomeDate при работе с моими пользовательскими компонентами графического интерфейса.

Однако вы увидите, что они чаще всего используются вне среды прямого кодирования. Например, конструктор Windows широко использует их, поэтому знает, как работать с объектами, созданными по индивидуальному заказу. Используя BrowsableAttribute следующим образом:

[Browsable(false)]
public SomeCustomType DontShowThisInTheDesigner
{
    get{/*do something*/}
}

Сообщает дизайнеру, чтобы он не указывал это в доступных свойствах в окне «Свойства», например, во время разработки.

Вы мог также используете их для генерации кода, операций предварительной компиляции (таких как Post-Sharp) или операций времени выполнения, таких как Reflection.Emit. Например, вы могли бы написать небольшой код для профилирования, который прозрачно обертывал бы каждый вызов вашего кода и время его. Вы можете «отказаться» от времени с помощью атрибута, который вы помещаете в определенные методы.

public void SomeProfilingMethod(MethodInfo targetMethod, object target, params object[] args)
{
    bool time = true;
    foreach (Attribute a in target.GetCustomAttributes())
    {
        if (a.GetType() is NoTimingAttribute)
        {
            time = false;
            break;
        }
    }
    if (time)
    {
        StopWatch stopWatch = new StopWatch();
        stopWatch.Start();
        targetMethod.Invoke(target, args);
        stopWatch.Stop();
        HandleTimingOutput(targetMethod, stopWatch.Duration);
    }
    else
    {
        targetMethod.Invoke(target, args);
    }
}

Объявить их легко, просто создайте класс, унаследованный от Attribute.

public class DisplayOrderAttribute : Attribute
{
    private int order;

    public DisplayOrderAttribute(int order)
    {
        this.order = order;
    }

    public int Order
    {
        get { return order; }
    }
}

И помните, что когда вы используете атрибут, вы можете опустить суффикс «атрибут», компилятор добавит его за вас.

Атрибуты ПРИМЕЧАНИЕ: сами по себе ничего не делают - нужен другой код, который их использует. Иногда этот код был написан для вас, но иногда вам приходится писать его самому. Например, компилятор C# заботится о некоторых, а некоторые фреймворки используют некоторые (например, NUnit ищет [TestFixture] в классе и [Test] в тестовом методе при загрузке сборки) .
Поэтому при создании собственного настраиваемого атрибута имейте в виду, что он вообще не повлияет на поведение вашего кода. Вам нужно будет написать другую часть, которая проверяет атрибуты (посредством отражения) и воздействует на них.

Как бы то ни было, это список всех (встроенных) атрибутов .NET: msdn.microsoft.com/en-us/library/aa311259(VS.71).aspx

wprl 28.09.2008 04:37

Как бы вы использовали свой SomeProfilingMethod в качестве атрибута?

RayLoveless 18.10.2016 01:16

@RayLoveless - это не атрибут, SomeProfilingMethod - это инструментальный код, который ищет атрибуты профилирования. В частности, в этом примере я дал поиск атрибута отказа (NoTimingAttribute), а не атрибута отказа. Идея в том, что это все время.

Quibblesome 18.10.2016 10:48

@Quibblesome, не могли бы вы добавить что-то вроде «Атрибуты ничего не делают сами по себе - для их использования нужен какой-то код Другой (компилятор заботится о паре, разные фреймворки используют некоторые). Простое создание атрибута не повлияет на поведение кода - вам нужно написать другую часть, которая проверяет атрибуты (через отражение) и воздействует на них ». (или я могу это сделать, если вы в порядке). Многие люди ожидают, что атрибуты будут волшебным образом работать, и ни один из приведенных здесь ответов не проясняет это. (или просто ссылку на stackoverflow.com/questions/4879521/…, который его покрывает)

Alexei Levenkov 05.02.2019 21:05

только если вы перестанете использовать Bing. Неа. j / k Я использую DuckDuckGo в качестве основного, который в основном использует Bing iirc. :)

Quibblesome 05.02.2019 22:26

Кстати, у вас есть какие-нибудь ссылки на неудачные ожидания разработчиков в отношении функций? Это очень интересная тема, особенно учитывая, насколько хорошо была написана базовая структура для содействия самопознанию.

Quibblesome 05.02.2019 22:32

Атрибуты - это своего рода метаданные для тегов классов. Это часто используется в WinForms, например, для скрытия элементов управления с панели инструментов, но может быть реализовано в вашем собственном приложении, чтобы позволить экземплярам различных классов вести себя определенным образом.

Начнем с создания атрибута:

[AttributeUsage(AttributeTargets.Class, AllowMultiple=false, Inherited=true)]
public class SortOrderAttribute : Attribute
{
    public int SortOrder { get; set; }

    public SortOrderAttribute(int sortOrder)
    {
        this.SortOrder = sortOrder;
    }
}

Чтобы все классы атрибутов были действительными, они должны иметь суффикс Attribute.
После этого создайте класс, использующий атрибут.

[SortOrder(23)]
public class MyClass
{
    public MyClass()
    {
    }
}

Теперь вы можете проверить конкретный класс SortOrderAttribute (если он есть), выполнив следующие действия:

public class MyInvestigatorClass
{
    public void InvestigateTheAttribute()
    {
        // Get the type object for the class that is using
        // the attribute.
        Type type = typeof(MyClass);

        // Get all custom attributes for the type.
        object[] attributes = type.GetCustomAttributes(
            typeof(SortOrderAttribute), true);

        // Now let's make sure that we got at least one attribute.
        if (attributes != null && attributes.Length > 0)
        {
            // Get the first attribute in the list of custom attributes
            // that is of the type "SortOrderAttribute". This should only
            // be one since we said "AllowMultiple=false".
            SortOrderAttribute attribute = 
                attributes[0] as SortOrderAttribute;

            // Now we can get the sort order for the class "MyClass".
            int sortOrder = attribute.SortOrder;
        }
    }
}

Если вы хотите узнать больше об этом, вы всегда можете проверить MSDN, у которого есть довольно хорошее описание. Надеюсь, это вам помогло!

Как уже было сказано, атрибуты создать относительно легко. Другая часть работы - это создание кода, который его использует. В большинстве случаев вы будете использовать отражение во время выполнения, чтобы изменить поведение в зависимости от наличия атрибута или его свойств. Есть также сценарии, в которых вы будете проверять атрибуты в скомпилированном коде, чтобы провести какой-то статический анализ. Например, параметры могут быть помечены как ненулевые, и инструмент анализа может использовать это как подсказку.

Использование атрибутов и знание соответствующих сценариев их использования - это основная работа.

В проекте, над которым я сейчас работаю, есть набор объектов пользовательского интерфейса различных видов и редактор для сборки этих объектов для создания страниц для использования в основном приложении, что немного похоже на конструктор форм в DevStudio. Эти объекты существуют в своей собственной сборке, и каждый объект является классом, производным от UserControl, и имеет настраиваемый атрибут. Этот атрибут определяется следующим образом:

[AttributeUsage (AttributeTargets::Class)]
public ref class ControlDescriptionAttribute : Attribute
{
public:
  ControlDescriptionAttribute (String ^name, String ^description) :
    _name (name),
    _description (description)
  {
  }

  property String ^Name
  {
    String ^get () { return _name; }
  }

  property String ^Description
  {
    String ^get () { return _description; }
  }

private:
  String
    ^ _name,
    ^ _description;
};

и я применяю его к такому классу:

[ControlDescription ("Pie Chart", "Displays a pie chart")]
public ref class PieControl sealed : UserControl
{
  // stuff
};

что было сказано на предыдущих плакатах.

Для использования атрибута в редакторе есть Generic::List <Type>, содержащий типы элементов управления. Существует список, который пользователь может перетащить на страницу, чтобы создать экземпляр элемента управления. Чтобы заполнить поле списка, я беру ControlDescriptionAttribute для элемента управления и заполняю запись в списке:

// done for each control type
array <Object ^>
  // get all the custom attributes
  ^attributes = controltype->GetCustomAttributes (true);

Type
  // this is the one we're interested in
  ^attributetype = ECMMainPageDisplay::ControlDescriptionAttribute::typeid;

// iterate over the custom attributes
for each (Object ^attribute in attributes)
{
  if (attributetype->IsInstanceOfType (attribute))
  {
    ECMMainPageDisplay::ControlDescriptionAttribute
      ^description = safe_cast <ECMMainPageDisplay::ControlDescriptionAttribute ^> (attribute);

    // get the name and description and create an entry in the list
    ListViewItem
      ^item = gcnew ListViewItem (description->Name);

    item->Tag = controltype->Name;
    item->SubItems->Add (description->Description);

    mcontrols->Items->Add (item);
    break;
  }
}

Примечание: это C++ / CLI, но преобразовать его в C# несложно. (да, я знаю, C++ / CLI - мерзость, но это то, с чем мне приходится работать :-()

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

Как только вы получите всю идею, вы удивитесь, как вы когда-либо жили без них.

Атрибуты - это, по сути, биты данных, которые вы хотите прикрепить к вашему типы (классы, методы, события, перечисления и т. д.)

Идея состоит в том, что во время выполнения какой-то другой тип / фреймворк / инструмент будет запрашивать у типа ваш информацию в атрибуте и действовать в соответствии с ней.

Так, например, Visual Studio может запрашивать атрибуты стороннего элемента управления, чтобы выяснить, какие свойства элемента управления должны отображаться на панели «Свойства» во время разработки.

Атрибуты также могут использоваться в аспектно-ориентированном программировании для внедрения / управления объектами во время выполнения на основе атрибутов, которые их украшают, и добавления к объектам проверки, ведения журнала и т. д., Не затрагивая бизнес-логику объекта.

Чтобы приступить к созданию атрибута, откройте исходный файл C#, введите attribute и нажмите [TAB]. Он будет расширен до шаблона для нового атрибута.

Как он отвечает на вопрос? это должен быть комментарий, а не ответ.

gdoron is supporting Monica 18.11.2014 10:40

Многие ответили, но пока никто об этом не упомянул ...

Атрибуты часто используются с отражением. Отражение уже идет довольно медленно.

очень стоящий отмечает ваши настраиваемые атрибуты как классы sealed для повышения их производительности во время выполнения.

Также неплохо подумать, где было бы уместно использовать такой атрибут, и присвоить свой атрибут (!), Чтобы указать это через AttributeUsage. Список доступных вариантов использования атрибутов может вас удивить:

  • сборка
  • Модуль
  • Учебный класс
  • Struct
  • Enum
  • Конструктор
  • Методика
  • Свойство
  • Поле
  • Мероприятие
  • Интерфейс
  • Параметр
  • Делегат
  • ReturnValue
  • GenericParameter
  • Все

Также здорово, что атрибут AttributeUsage является частью подписи атрибута AttributeUsage. Привет круговым зависимостям!

[AttributeUsageAttribute(AttributeTargets.Class, Inherited = true)]
public sealed class AttributeUsageAttribute : Attribute

Атрибуты также обычно используются для аспектно-ориентированного программирования. Для примера посмотрите проект PostSharp.

Другие вопросы по теме