Какие атрибуты в .NET? - PullRequest
       57

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

200 голосов
/ 21 августа 2008

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

Ответы [ 11 ]

143 голосов
/ 21 августа 2008

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

Например, я мог бы объявить Атрибут с именем: 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 Designer широко использует их, поэтому знает, как обращаться с объектами, сделанными на заказ. Использование 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] в тестовом методе при загрузке сборки).
Поэтому при создании собственного настраиваемого атрибута следует учитывать, что он никак не повлияет на поведение вашего кода. Вам нужно написать другую часть, которая проверяет атрибуты (через отражение) и воздействует на них.

35 голосов
/ 16 февраля 2009

Многие люди ответили, но никто до сих пор не упомянул об этом ...

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

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

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

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

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

[AttributeUsageAttribute(AttributeTargets.Class, Inherited = true)]
public sealed class AttributeUsageAttribute : Attribute
12 голосов
/ 21 августа 2008

Атрибуты являются разновидностью метаданных для маркировки классов. Это часто используется в 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 , который имеет довольно хорошее описание.
Я надеюсь, что это помогло вам!

4 голосов
/ 21 августа 2008

В проекте, над которым я сейчас работаю, есть набор объектов пользовательского интерфейса различных типов и редактор для сборки этих объектов для создания страниц для использования в основном приложении, немного похоже на дизайнер форм в 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 голосов
/ 21 августа 2008

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

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

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

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

4 голосов
/ 21 августа 2008

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

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

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

3 голосов
/ 21 августа 2008

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

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

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

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

3 голосов
/ 21 августа 2008

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

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

2 голосов
/ 27 декабря 2008

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

2 голосов
/ 21 августа 2008

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

Учебное пособие http://msdn.microsoft.com/en-us/library/aa288454(VS.71).aspx

...