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