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


Відповіді:


146

Метадані. Дані про ваші об’єкти / методи / властивості.

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

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 широко використовує їх, щоб він знав, як поводитися з об'єктами на замовлення. Використовуючи BrowvableAttribute так:

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

Показує дизайнеру не перераховувати це в доступних властивостях, наприклад, у вікні "Властивості" на час проектування.

Ви могли б також використовувати їх для генерації коду, попередньої компіляції операцій (наприклад, пост-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] на метод тесту при завантаженні збірки).
Тож створюючи власний спеціальний атрибут, майте на увазі, що це зовсім не вплине на поведінку вашого коду. Вам потрібно буде написати іншу частину, яка перевіряє атрибути (через відображення) та діє на них.


32
Для чого це варто, це список усіх (вбудованих) атрибутів .NET: msdn.microsoft.com/en-us/library/aa311259(VS.71).aspx
wprl

1
Як би ви використовували ваш "SomeProfilingMethod" як атрибут?
RayLoveless

@RayLoveless це не атрибут, SomeProfilingMethod - це інструментальний код, який шукає атрибути профілювання. Зокрема, у прикладі я шукав атрибут "відмови" (NoTimingAttribute) на відміну від "відмови". Ідея полягає в тому, що це часом все.
Химерний

@Quibblesome ви можете додати щось на кшталт "Атрибути не роблять нічого самостійно - для їх використання повинен бути якийсь інший код (компілятор піклується про пару, різні рамки використовують деякі). Просто створення атрибута не вплине на поведінку коду - вам потрібно написати іншу частину, яка перевіряє атрибути (через відображення) та діє на них ". (або я можу це зробити, якщо у вас все в порядку). Багато людей очікують, що атрибути магічно працюють, і жодна з відповідей не пояснює це. (або просто посилання на stackoverflow.com/questions/4879521/…, що його охоплює)
Олексій Левенков

тільки якщо ви припините використовувати Bing. Ні. j / k Я використовую DuckDuckGo як основний, який в основному використовує Bing iirc. :)
Дивовижна

36

Багато людей відповіли, але поки ніхто про це не згадував ...

Атрибути сильно використовуються з відображенням. Рефлексія вже досить повільна.

Це дуже корисно маркування призначених для користувача атрибутів як sealedкласи , щоб поліпшити їх продуктивність у час виконання.

Також добре подумати, де було б доцільно використати такий атрибут, і атрибутом (!) Позначити це через AttributeUsage. Перелік доступних атрибутів може здивувати вас:

  • Асамблея
  • Модуль
  • Клас
  • Структуру
  • Енум
  • Конструктор
  • Метод
  • Власність
  • Поле
  • Подія
  • Інтерфейс
  • Параметр
  • Делегат
  • ReturnValue
  • Загальний параметр
  • Усі

Також здорово, що атрибут AttributeUsage є частиною підпису атрибута AttributeUsage. Охочі за кругові залежності!

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

13

Атрибути - це свого роду метадані для тегів класів. Це часто використовується в WinForms, наприклад, для приховування елементів керування на панелі інструментів, але може бути реалізовано у вашому власному додатку для того, щоб екземпляри різних класів могли поводитися певними способами.

Почніть зі створення атрибута:

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

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

Усі класи атрибутів повинні мати суфікс "Атрибут", щоб бути дійсним.
Після цього створіть клас, який використовує атрибут.

[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, який має досить хороший опис.
Я сподіваюся, що це вам допомогло!


5

Атрибут - це клас, який містить деякий біт функціональності, який ви можете застосувати до об'єктів у своєму коді. Щоб створити його, створіть клас, який успадковується від System.Attribute.

Щодо того, для чого вони гарні ... їх використання майже необмежене.

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


1
"функціональність" - це неправильне слово; вони є метаданими, а не функціональністю
Marc Gravell

5

Атрибути - це як метадані, застосовані до класів, методів або збірок.

Вони корисні для будь-якої кількості речей (візуалізація налагоджувача, маркування речей як застарілих, позначення речей як серіалізаційних, список нескінченний).

Створити власні власні замовлення легко як пиріг. Починай тут:

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


5

У проекті, над яким я зараз працюю, є набір UI-об’єктів різного смаку та редактор для збирання цих об’єктів для створення сторінок для використання в основному додатку, трохи схожий на дизайнер форми у 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 - це гидота, але з цим я маю працювати :-()

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

Як тільки ви зрозумієте всю ідею, ви задумаєтесь, як ви коли-небудь жили без них.


4

Як було сказано, атрибути можна створити відносно просто. Інша частина роботи - це створення коду, який його використовує. У більшості випадків ви використовуєте відображення під час виконання, щоб змінити поведінку на основі наявності атрибута або його властивостей. Також є сценарії, коли ви будете перевіряти атрибути на складеному коді, щоб зробити якийсь статичний аналіз. Наприклад, параметри можуть бути позначені як ненульові, і інструмент аналізу може використовувати це як підказку.

Використання атрибутів та знання відповідних сценаріїв їх використання - основна частина роботи.


3

Атрибути - це, по суті, біти даних, які ви хочете долучити до своїх типів (класи, методи, події, перерахунки тощо)

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

Так, наприклад, Visual Studio може запитувати атрибути на сторонній елемент управління, щоб визначити, які властивості елемента керування повинні з’являтися на панелі властивостей під час проектування.

Атрибути можуть також використовуватися в програмі, орієнтованому на аспекти, для введення / маніпулювання об'єктами під час виконання на основі атрибутів, які їх декорують та додають до об'єктів перевірку, реєстрацію тощо, не впливаючи на ділову логіку об'єкта.


2

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

Підручник на сайті http://msdn.microsoft.com/en-us/library/aa288454(VS.71).aspx


2

Щоб розпочати створення атрибута, відкрийте вихідний файл C #, введіть attributeта натисніть [TAB]. Він розшириться до шаблону для нового атрибута.


6
Як це відповідає на запитання? це повинен бути коментар, а не відповідь.
gdoron підтримує Моніку

1

Атрибути також часто використовуються для програмування, орієнтованого на аспекти. Для прикладу цього ознайомтеся з проектом PostSharp .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.