Самые полезные атрибуты
Я знаю, что атрибуты чрезвычайно полезны. Есть некоторые предопределенные, такие как [Browsable(false)]
который позволяет скрыть свойства на вкладке свойств. Вот хороший вопрос, объясняющий атрибуты: что такое атрибуты в.NET?
Какие предопределенные атрибуты (и их пространство имен) вы фактически используете в своих проектах?
32 ответа
[DebuggerDisplay]
может быть действительно полезным, чтобы быстро увидеть настроенный вывод Type при наведении указателя мыши на экземпляр Type во время отладки. пример:
[DebuggerDisplay("FirstName={FirstName}, LastName={LastName}")]
class Customer
{
public string FirstName;
public string LastName;
}
Вот как это должно выглядеть в отладчике:
Также стоит отметить, что [WebMethod]
приписать с CacheDuration
набор свойств может избежать ненужного выполнения метода веб-службы.
System.Obsolete
это один из самых полезных атрибутов в рамках, на мой взгляд. Возможность поднять предупреждение о коде, который больше не должен использоваться, очень полезна. Мне нравится иметь возможность сказать разработчикам, что что-то больше не должно использоваться, а также способ объяснить, почему и указать на лучший / новый способ сделать что-то.
Conditional attribute
это довольно удобно для отладки. Это позволяет вам добавлять методы в ваш код для целей отладки, которые не будут компилироваться при сборке вашего решения для выпуска.
Кроме того, есть много атрибутов, специфичных для веб-элементов управления, которые я считаю полезными, но они более специфичны и не имеют никакого применения вне разработки серверных элементов управления из того, что я обнаружил.
[Flags]
довольно удобно Синтаксический сахар, конечно, но все же довольно приятный.
[Flags]
enum SandwichStuff
{
Cheese = 1,
Pickles = 2,
Chips = 4,
Ham = 8,
Eggs = 16,
PeanutButter = 32,
Jam = 64
};
public Sandwich MakeSandwich(SandwichStuff stuff)
{
Console.WriteLine(stuff.ToString());
// ...
}
// ...
MakeSandwich(SandwichStuff.Cheese
| SandwichStuff.Ham
| SandwichStuff.PeanutButter);
// produces console output: "Cheese, Ham, PeanutButter"
Леппи указывает на то, чего я не осознавал, и что скорее ослабляет мой энтузиазм по поводу этого атрибута: он не дает указанию компилятору разрешать комбинации битов в качестве допустимых значений для переменных перечисления, компилятор допускает это для перечислений независимо. Мой C++ фон показывает через... вздох
Мне нравится [DebuggerStepThrough]
от System.Diagnostics.
Это очень удобно для того, чтобы не заходить в эти однострочные ничего не используемые методы или свойства (если вы вынуждены работать в ранних версиях.Net без автоматических свойств). Поместите атрибут в короткий метод или метод получения или установки свойства, и вы будете лететь прямо, даже когда нажмете "шаг в" в отладчике.
Для чего это стоит, вот список всех атрибутов.NET. Есть несколько сотен.
Я не знаю ни о ком другом, но у меня есть серьезные RTFM, чтобы сделать!
Мой голос будет за [Conditional]
[Conditional("DEBUG")]
public void DebugOnlyFunction()
{
// your code here
}
Вы можете использовать это, чтобы добавить функцию с расширенными функциями отладки; лайк Debug.Write
, он вызывается только в отладочных сборках и поэтому позволяет инкапсулировать сложную логику отладки вне основного потока вашей программы.
Я всегда использую DisplayName
, Description
а также DefaultValue
атрибуты общедоступных свойств моих пользовательских элементов управления, пользовательских элементов управления или любого класса, который я буду редактировать через сетку свойств. Эти теги используются.NET PropertyGrid для форматирования имени, панели описания и значений, выделенных жирным шрифтом, для которых не установлены значения по умолчанию.
[DisplayName("Error color")]
[Description("The color used on nodes containing errors.")]
[DefaultValue(Color.Red)]
public Color ErrorColor
{
...
}
Я просто хотел бы, чтобы IntelliSense Visual Studio взял бы Description
атрибут в учетную запись, если XML-комментарий не найден. Это позволит избежать повторения одного и того же предложения дважды.
[Serializable]
используется все время для сериализации и десериализации объектов в и из внешних источников данных, таких как xml или с удаленного сервера. Подробнее об этом здесь.
В духе Хофштадта [Attribute]
Атрибут очень полезен, поскольку именно так вы создаете свои собственные атрибуты. Я использовал атрибуты вместо интерфейсов для реализации систем плагинов, добавления описаний в Enums, имитации нескольких рассылок и других приемов.
Вот пост об интересном атрибуте InternalsVisibleTo. В основном то, что он делает, имитирует функциональность доступа друзей C++. Это очень удобно для модульного тестирования.
Я бы предложил [TestFixture]
а также [Test]
- из библиотеки nUnit.
Модульные тесты в вашем коде обеспечивают безопасность при рефакторинге и кодированной документации.
[XmlIgnore]
поскольку это позволяет игнорировать (в любой сериализации xml) "родительские" объекты, которые в противном случае могли бы вызвать исключения при сохранении.
Он не имеет правильного имени, не поддерживается в фреймворке и не требует параметра, но этот атрибут является полезным маркером для неизменяемых классов:
[ImmutableObject(true)]
Мне нравится использовать [ThreadStatic]
атрибут в сочетании с программированием на основе потоков и стеков. Например, если я хочу значение, которым я хочу поделиться с остальной частью последовательности вызовов, но я хочу сделать это вне диапазона (то есть вне параметров вызова), я мог бы использовать что-то вроде этого.
class MyContextInformation : IDisposable {
[ThreadStatic] private static MyContextInformation current;
public static MyContextInformation Current {
get { return current; }
}
private MyContextInformation previous;
public MyContextInformation(Object myData) {
this.myData = myData;
previous = current;
current = this;
}
public void Dispose() {
current = previous;
}
}
Позже в моем коде я могу использовать это для предоставления контекстной информации вне группы людям, находящимся ниже по потоку от моего кода. Пример:
using(new MyContextInformation(someInfoInContext)) {
...
}
Атрибут ThreadStatic позволяет мне охватить вызов только рассматриваемым потоком, избегая беспорядочной проблемы доступа к данным через потоки.
DebuggerHiddenAttribute, который позволяет избежать шага в коде, который не следует отлаживать.
public static class CustomDebug
{
[DebuggerHidden]
public static void Assert(Boolean condition, Func<Exception> exceptionCreator) { ... }
}
...
// The following assert fails, and because of the attribute the exception is shown at this line
// Isn't affecting the stack trace
CustomDebug.Assert(false, () => new Exception());
Также он не позволяет показывать методы в трассировке стека, что полезно, когда есть метод, который просто оборачивает другой метод:
[DebuggerHidden]
public Element GetElementAt(Vector2 position)
{
return GetElementAt(position.X, position.Y);
}
public Element GetElementAt(Single x, Single y) { ... }
Если вы сейчас позвоните GetElementAt(new Vector2(10, 10))
и возникает ошибка в упакованном методе, стек вызовов не показывает метод, который вызывает метод, который выдает ошибку.
DesignerSerializationVisibilityAttribute
это очень полезно. Когда вы помещаете свойство среды выполнения в элемент управления или компонент и не хотите, чтобы дизайнер сериализировал его, вы используете его следующим образом:
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public Foo Bar {
get { return baz; }
set { baz = value; }
}
Только несколько атрибутов получают поддержку компилятора, но одно очень интересное использование атрибутов в AOP: PostSharp использует ваши собственные атрибуты для внедрения IL в методы, позволяя использовать всевозможные возможности... log/trace - тривиальные примеры - но некоторые другие хорошие примеры такие вещи, как автоматическая реализация INotifyPropertyChanged ( здесь).
Некоторые из них возникают непосредственно и влияют на компилятор или среду выполнения:
[Conditional("FOO")]
- вызовы этого метода (включая оценку аргумента) происходят только в том случае, если во время сборки определен символ "FOO"[MethodImpl(...)]
- используется для обозначения нескольких вещей, таких как синхронизация, встраивание[PrincipalPermission(...)]
- используется для автоматической проверки безопасности кода[TypeForwardedTo(...)]
- используется для перемещения типов между сборками без перестройки вызывающих
Для вещей, которые проверяются вручную с помощью отражения - я большой поклонник System.ComponentModel
атрибуты; вещи как [TypeDescriptionProvider(...)]
, [TypeConverter(...)]
, а также [Editor(...)]
который может полностью изменить поведение типов в сценариях привязки данных (т. е. динамические свойства и т. д.).
Если бы мне пришлось сканировать покрытие кода, я думаю, что эти два были бы лучшими:
[Serializable]
[WebMethod]
Я использовал [DataObjectMethod]
недавно. Он описывает метод, чтобы вы могли использовать свой класс с ObjectDataSource (или другими элементами управления).
[DataObjectMethod(DataObjectMethodType.Select)]
[DataObjectMethod(DataObjectMethodType.Delete)]
[DataObjectMethod(DataObjectMethodType.Update)]
[DataObjectMethod(DataObjectMethodType.Insert)]
В нашем текущем проекте мы используем
[ComVisible(false)]
Он контролирует доступность отдельного управляемого типа или элемента или всех типов в сборке для COM.
[TypeConverter(typeof(ExpandableObjectConverter))]
Говорит конструктору расширить свойства, которые являются классами (вашего контроля)
[Obfuscation]
Указывает инструментам запутывания выполнять указанные действия для сборки, типа или элемента. (Хотя обычно вы используете уровень сборки [assembly:ObfuscateAssemblyAttribute(true)]
Атрибуты, которые я использую больше всего, относятся к сериализации XML.
XmlRoot
XmlElement
XmlAttribute
так далее...
Чрезвычайно полезно при выполнении любого быстрого и грязного анализа или сериализации XML.
Мне нравится быть разработчиком среднего уровня
System.ComponentModel.EditorBrowsableAttribute
Позволяет мне скрывать свойства, чтобы разработчик пользовательского интерфейса не был перегружен свойствами, которые они не должны видеть.
System.ComponentModel.BindableAttribute
Некоторые вещи не должны быть привязаны к данным. Опять же, уменьшает работу, которую должны сделать разработчики пользовательского интерфейса.
Мне тоже нравится DefaultValue
что Лоуренс Джонстон упомянул.
System.ComponentModel.BrowsableAttribute
и Flags
используются регулярно.
я использую System.STAThreadAttribute
System.ThreadStaticAttribute
при необходимости.
Кстати. Я так же ценен для всех разработчиков.Net Framework.
[EditorBrowsable(EditorBrowsableState.Never)]
позволяет скрыть свойства и методы от IntelliSense, если проект не входит в ваше решение. Очень полезно для сокрытия недопустимых потоков для беглых интерфейсов. Как часто вы хотите GetHashCode() или Equals()?
Для MVC [ActionName("Name")]
позволяет использовать действие Get и Post с одной и той же сигнатурой метода или использовать тире в имени действия, что в противном случае было бы невозможно без создания для него маршрута.
Я считаю важным упомянуть здесь, что следующие атрибуты также очень важны:
STAThreadAttribute
Указывает, что модель потока COM для приложения является однопоточным (STA).
Например, этот атрибут используется в приложениях Windows Forms:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
А также...
SuppressMessageAttribute
Подавляет создание отчетов о конкретном нарушении правил инструмента статического анализа, что позволяет использовать несколько подавлений для одного артефакта кода.
Например:
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "isChecked")]
[SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals", MessageId = "fileIdentifier")]
static void FileNode(string name, bool isChecked)
{
string fileIdentifier = name;
string fileName = name;
string version = String.Empty;
}
Вдобавок ко всему, вот краткий список, примерно отсортированный по частоте использования, предопределенных атрибутов, которые я фактически использую в большом проекте (~500 тыс. LoC):
Флаги, Сериализуемый, WebMethod, COMVisible, TypeConverter, Условный, ThreadStatic, Устаревший, InternalsVisibleTo, DebuggerStepThrough.
Я генерирую класс сущности данных через CodeSmith и использую атрибуты для некоторой процедуры проверки. Вот пример:
/// <summary>
/// Firm ID
/// </summary>
[ChineseDescription("送样单位编号")]
[ValidRequired()]
public string FirmGUID
{
get { return _firmGUID; }
set { _firmGUID = value; }
}
И я получил служебный класс для проверки на основе атрибутов, прикрепленных к классу сущностей данных. Вот код:
namespace Reform.Water.Business.Common
{
/// <summary>
/// Validation Utility
/// </summary>
public static class ValidationUtility
{
/// <summary>
/// Data entity validation
/// </summary>
/// <param name="data">Data entity object</param>
/// <returns>return true if the object is valid, otherwise return false</returns>
public static bool Validate(object data)
{
bool result = true;
PropertyInfo[] properties = data.GetType().GetProperties();
foreach (PropertyInfo p in properties)
{
//Length validatioin
Attribute attribute = Attribute.GetCustomAttribute(p,typeof(ValidLengthAttribute), false);
if (attribute != null)
{
ValidLengthAttribute validLengthAttribute = attribute as ValidLengthAttribute;
if (validLengthAttribute != null)
{
int maxLength = validLengthAttribute.MaxLength;
int minLength = validLengthAttribute.MinLength;
string stringValue = p.GetValue(data, null).ToString();
if (stringValue.Length < minLength || stringValue.Length > maxLength)
{
return false;
}
}
}
//Range validation
attribute = Attribute.GetCustomAttribute(p,typeof(ValidRangeAttribute), false);
if (attribute != null)
{
ValidRangeAttribute validRangeAttribute = attribute as ValidRangeAttribute;
if (validRangeAttribute != null)
{
decimal maxValue = decimal.MaxValue;
decimal minValue = decimal.MinValue;
decimal.TryParse(validRangeAttribute.MaxValueString, out maxValue);
decimal.TryParse(validRangeAttribute.MinValueString, out minValue);
decimal decimalValue = 0;
decimal.TryParse(p.GetValue(data, null).ToString(), out decimalValue);
if (decimalValue < minValue || decimalValue > maxValue)
{
return false;
}
}
}
//Regex validation
attribute = Attribute.GetCustomAttribute(p,typeof(ValidRegExAttribute), false);
if (attribute != null)
{
ValidRegExAttribute validRegExAttribute = attribute as ValidRegExAttribute;
if (validRegExAttribute != null)
{
string objectStringValue = p.GetValue(data, null).ToString();
string regExString = validRegExAttribute.RegExString;
Regex regEx = new Regex(regExString);
if (regEx.Match(objectStringValue) == null)
{
return false;
}
}
}
//Required field validation
attribute = Attribute.GetCustomAttribute(p,typeof(ValidRequiredAttribute), false);
if (attribute != null)
{
ValidRequiredAttribute validRequiredAttribute = attribute as ValidRequiredAttribute;
if (validRequiredAttribute != null)
{
object requiredPropertyValue = p.GetValue(data, null);
if (requiredPropertyValue == null || string.IsNullOrEmpty(requiredPropertyValue.ToString()))
{
return false;
}
}
}
}
return result;
}
}
}
[DeploymentItem("myFile1.txt")]
Документ MSDN по DeploymentItem
Это действительно полезно, если вы тестируете файл или используете файл в качестве входных данных для вашего теста.
[System.Security.Permissions.PermissionSetAttribute]
позволяет применять меры безопасности для PermissionSet к коду с использованием декларативной безопасности.
// usage:
public class FullConditionUITypeEditor : UITypeEditor
{
// The immediate caller is required to have been granted the FullTrust permission.
[PermissionSetAttribute(SecurityAction.LinkDemand, Name = "FullTrust")]
public FullConditionUITypeEditor() { }
}