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





Атрибут - это класс, который содержит некоторые функции, которые вы можете применить к объектам в вашем коде. Чтобы создать его, создайте класс, наследующий от System.Attribute.
Что касается того, для чего они годны ... их применение практически безгранично.
http://www.codeproject.com/KB/cs/dotnetattributes.aspx
Атрибуты подобны метаданным, применяемым к классам, методам или сборкам.
Они хороши для любого количества вещей (визуализация отладчика, маркировка вещей как устаревших, маркировка вещей как сериализуемых, список бесконечен).
Создать свои собственные - это просто, как пирог. Начни здесь:
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
Как бы вы использовали свой SomeProfilingMethod в качестве атрибута?
@RayLoveless - это не атрибут, SomeProfilingMethod - это инструментальный код, который ищет атрибуты профилирования. В частности, в этом примере я дал поиск атрибута отказа (NoTimingAttribute), а не атрибута отказа. Идея в том, что это все время.
@Quibblesome, не могли бы вы добавить что-то вроде «Атрибуты ничего не делают сами по себе - для их использования нужен какой-то код Другой (компилятор заботится о паре, разные фреймворки используют некоторые). Простое создание атрибута не повлияет на поведение кода - вам нужно написать другую часть, которая проверяет атрибуты (через отражение) и воздействует на них ». (или я могу это сделать, если вы в порядке). Многие люди ожидают, что атрибуты будут волшебным образом работать, и ни один из приведенных здесь ответов не проясняет это. (или просто ссылку на stackoverflow.com/questions/4879521/…, который его покрывает)
только если вы перестанете использовать Bing. Неа. j / k Я использую DuckDuckGo в качестве основного, который в основном использует Bing iirc. :)
Кстати, у вас есть какие-нибудь ссылки на неудачные ожидания разработчиков в отношении функций? Это очень интересная тема, особенно учитывая, насколько хорошо была написана базовая структура для содействия самопознанию.
Атрибуты - это своего рода метаданные для тегов классов. Это часто используется в 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]. Он будет расширен до шаблона для нового атрибута.
Как он отвечает на вопрос? это должен быть комментарий, а не ответ.
Многие ответили, но пока никто об этом не упомянул ...
Атрибуты часто используются с отражением. Отражение уже идет довольно медленно.
очень стоящий отмечает ваши настраиваемые атрибуты как классы sealed для повышения их производительности во время выполнения.
Также неплохо подумать, где было бы уместно использовать такой атрибут, и присвоить свой атрибут (!), Чтобы указать это через AttributeUsage. Список доступных вариантов использования атрибутов может вас удивить:
Также здорово, что атрибут AttributeUsage является частью подписи атрибута AttributeUsage. Привет круговым зависимостям!
[AttributeUsageAttribute(AttributeTargets.Class, Inherited = true)]
public sealed class AttributeUsageAttribute : Attribute
Атрибуты также обычно используются для аспектно-ориентированного программирования. Для примера посмотрите проект PostSharp.
«функциональность» - здесь неправильное слово; это метаданные, а не функциональность