Самые полезные атрибуты

739

Я знаю, что атрибуты чрезвычайно полезны. Существуют некоторые предопределенные, такие как [Browsable(false)], которые позволяют скрывать свойства на вкладке свойств. Вот хороший вопрос, объясняющий атрибуты: Что такое атрибуты в .NET?

Каковы предопределенные атрибуты (и их пространство имен), которые вы фактически используете в своих проектах?

  • 26
    Что за вопрос? , вся страница переполнена красивыми ответами с чудесными объяснениями. Пока я читаю это, у меня появился опыт, как опросить многих экспертов о своем мнении. +100 за вопрос.
Теги:
.net-attributes

32 ответа

652

[DebuggerDisplay] может быть очень полезно быстро увидеть индивидуальный вывод типа при наведении указателя мыши на экземпляр типа во время отладки. Пример:

[DebuggerDisplay("FirstName={FirstName}, LastName={LastName}")]
class Customer
{
    public string FirstName;
    public string LastName;
}

Вот как он должен выглядеть в отладчике:

alt text http://serialize.wordpress.com/files/2008/10/temp.jpg

Кроме того, стоит отметить, что атрибут [WebMethod] с набором свойств CacheDuration может избежать ненужного выполнения метода веб-службы.

  • 59
    Вау, это действительно приятно знать. Я обычно добивался того же, переопределяя ToString, но это лучше.
  • 16
    Будьте осторожны с этим, он отнимает гораздо больший кусок вашего процессора, чем ToString.
Показать ещё 7 комментариев
261

System.Obsolete является одним из самых полезных атрибутов в рамках, на мой взгляд. Очень полезно использовать возможность поднять предупреждение о коде, которое больше не должно использоваться. Мне нравится иметь возможность сказать разработчикам, что что-то больше не нужно использовать, а также способ объяснить, почему и указать на лучший/новый способ сделать что-то.

Conditional attribute также очень удобен для использования отладки. Это позволяет вам добавлять методы в код для целей отладки, которые не будут скомпилированы при создании вашего решения для выпуска.

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

  • 1
    Мне нравится устаревший флаг, но он просто вызывает предупреждение. Большинство людей, с которыми я столкнулся, игнорируют предупреждения в VS
  • 0
    Да, я тоже это заметил. Я работал над приложениями, где есть сотни предупреждений. Большинство из них должны были быть исправлены, но не по какой-либо причине. Я никогда этого не понимал ...
Показать ещё 9 комментариев
175

[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"

Leppie указывает на то, чего я не осознал, и который скорее ослабит мой энтузиазм по этому атрибуту: он не инструктирует компилятор разрешить битовые комбинации как допустимые значения для переменных перечисления компилятор допускает это для перечислений независимо. Мой фон С++ показывает... вздох

  • 0
    Так что именно делает атрибут Flags?
  • 0
    Я думаю, что перечисление должно наследоваться от int, не так ли?
Показать ещё 8 комментариев
168

Мне нравится [DebuggerStepThrough] из System.Diagnostics.

Это очень удобно для того, чтобы не вступать в эти однострочные методы do-nothing или свойства (если вы вынуждены работать в ранней .NET без автоматических свойств). Поместите атрибут на короткий метод или getter или setter свойства, и вы будете лететь прямо, даже если нажимаете "step into" в отладчике.

  • 5
    Так много раз я хотел бы знать об этой собственности
  • 1
    Просто позор, что он сломан замыканиями - см. Gregbeech.com/blogs/tech/archive/2008/10/17/… для получения дополнительной информации.
Показать ещё 4 комментария
131

Для чего стоит список всех атрибутов .NET. Есть несколько сотен.

Я не знаю ни о ком другом, но у меня есть серьезный RTFM!

  • 33
    опубликованный список для .net 1.1 вот список для 3.5 msdn.microsoft.com/en-us/library/system.attribute.aspx (нужно немного прокрутить вниз)
  • 2
    Обновил ссылку в вопросе. Теперь это полный список для 3.5
Показать ещё 4 комментария
119

Мое голосование будет за [Conditional]

[Conditional("DEBUG")]
public void DebugOnlyFunction()
{
    // your code here
}

Вы можете использовать это, чтобы добавить функцию с расширенными функциями отладки; например, Debug.Write, он вызывается только в отладочных сборках и поэтому позволяет инкапсулировать сложную логику отладки вне основного потока вашей программы.

  • 5
    разве это не то же самое, что делать #if DEBUG?
  • 10
    В некотором смысле, #if DEBUG означает, что вызывающий абонент также не должен вызывать его, в то время как Conditioinal оставляет вызов, но делает его NOP, который удаляется в JIT.
Показать ещё 2 комментария
84

Я всегда использую атрибуты DisplayName, Description и DefaultValue по общедоступным свойствам моих пользовательских элементов управления, настраиваемых элементов управления или любого класса, который я отредактирую через сетку свойств. Эти теги используются .NET PropertyGrid для форматирования имени, панели описания и жирных шрифтов, для которых не установлены значения по умолчанию.

[DisplayName("Error color")]
[Description("The color used on nodes containing errors.")]
[DefaultValue(Color.Red)]
public Color ErrorColor
{
    ...
} 

Я просто хочу, чтобы Visual Studio IntelliSense учитывала атрибут Description, если XML-комментарий не найден. Это позволит избежать повторения одного и того же предложения дважды.

  • 2
    Не могу поверить, что никто не указал Description пока вы не .. Это наиболее полезно для меня, когда используется с перечислениями ..
68

[Serializable] используется все время для сериализации и десериализации объектов в и из внешних источников данных, таких как xml или с удаленного сервера. Подробнее об этом здесь.

  • 0
    На самом деле он ссылается на psuedoattribute, поскольку C # испускает флаг метаданных для [Serializable], а не экземпляр пользовательского атрибута;)
  • 1
    Хотя очень полезный [Serializable] далеко не идеален. Для достижения желаемого результата требуется слишком много работы и проб и ошибок.
Показать ещё 3 комментария
52

В стиле Hofstadtian атрибут [Attribute] очень полезен, поскольку он создает ваши собственные атрибуты. Я использовал атрибуты вместо интерфейсов для реализации систем плагина, добавления описаний в Enums, имитации множественной отправки и других трюков.

  • 12
    Звучит круто! Не могли бы вы показать несколько примеров системы плагинов и описания enum? Это обе вещи, которые я заинтересован в реализации себя!
39

Здесь - сообщение об интересном атрибуте InternalsVisibleTo. В основном, что он делает, он имитирует функциональность доступа друзей С++. Это очень удобно для модульного тестирования.

  • 7
    Разве вы не имеете в виду удобный для взлома юнит-тест на что-то, что не может / не должно быть проверено?
  • 0
    @the_drow: Вы говорите о «частных средствах доступа»: msdn.microsoft.com/en-us/library/ms184807%28v=vs.80%29.aspx
Показать ещё 4 комментария
39

Я нашел [DefaultValue], чтобы быть весьма полезным.

27

Я предлагаю [TestFixture] и [Test] - из библиотеки nUnit.

Единичные тесты в вашем коде обеспечивают безопасность в рефакторинге и кодифицированной документации.

25

Он не хорошо назван, не поддерживается в рамках и не требует параметра, но этот атрибут является полезным маркером для неизменяемых классов:

[ImmutableObject(true)]
  • 6
    Согласно документации, используется только во время разработки (к сожалению).
  • 0
    Учитывая, что это только время разработки, возможно, было бы лучше создать свой собственный класс ImmutableObjectAttribute - по крайней мере, вы могли бы исключить этот параметр.
24
[XmlIgnore]

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

23

Мне нравится использовать атрибут [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 позволяет мне отображать вызов только в рассматриваемом потоке, избегая беспорядочной проблемы доступа к данным по потокам.

  • 0
    а как получить доступ то? Не понимаю смысл вашего примера использования здесь. Вы можете объяснить?
  • 0
    @Beachwalker Current должен быть статичным, отредактировал его сейчас. Теперь вы можете получить доступ к MyContextInformation.Current чтобы получить активный контекст в стеке. В некоторых случаях это очень хорошая концепция, наша (моя компания) система использует ее для многих целей.
20

DesignerSerializationVisibilityAttribute очень полезен. Когда вы кладете свойство runtime на элемент управления или компонент, и вы не хотите, чтобы конструктор сериализовал его, вы используете его следующим образом:

[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public Foo Bar {
    get { return baz; }
    set { baz = value; }
}
  • 4
    очень полезно для компонентов WinForms. использовать совместно с [Browsable (false)]
  • 3
    Хорошая мысль - [Browsable(false)] требуется, чтобы скрыть его от пользователя дизайнера, где требуется [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] чтобы его не сериализовать.
18

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)) и возникает ошибка при завершенном методе, стек вызовов не показывает метод, вызывающий метод, который выдает ошибку.

15

В последнее время я использую [DataObjectMethod]. Он описывает метод, чтобы вы могли использовать свой класс с ObjectDataSource (или другими элементами управления).

[DataObjectMethod(DataObjectMethodType.Select)] 
[DataObjectMethod(DataObjectMethodType.Delete)] 
[DataObjectMethod(DataObjectMethodType.Update)] 
[DataObjectMethod(DataObjectMethodType.Insert)] 

Дополнительная информация

15

Только несколько атрибутов получают поддержку компилятора, но одно очень интересное использование атрибутов в AOP: PostSharp использует ваши специальные атрибуты для ввода IL в методы, позволяющие всевозможные способности... log/trace - тривиальные примеры, но некоторые другие хорошие примеры - это такие вещи, как автоматическая реализация INotifyPropertyChanged (здесь).

Некоторые, которые возникают и напрямую влияют на компилятор или время выполнения:

  • [Conditional("FOO")] - вызовы этого метода (включая оценку аргументов) возникают только в том случае, если символ "FOO" определен во время сборки
  • [MethodImpl(...)] - используется для обозначения нескольких вещей, таких как синхронизация, вложение
  • [PrincipalPermission(...)] - используется для автоматического ввода проверок безопасности в код
  • [TypeForwardedTo(...)] - используется для перемещения типов между сборками без восстановления вызывающих абонентов.

Для вещей, которые проверяются вручную с помощью отражения - я большой поклонник атрибутов System.ComponentModel; такие вещи, как [TypeDescriptionProvider(...)], [TypeConverter(...)] и [Editor(...)], которые могут полностью изменить поведение типов в сценариях привязки данных (т.е. динамические свойства и т.д.).

14

Если мне нужно выполнить обход покрытия кода, я думаю, что эти два будут верхними:

 [Serializable]
 [WebMethod]
  • 15
    [WebMethod] используется для оформления метода, который предоставляется в веб-сервисе. [Сериализуемый] помечает ваши объекты так, чтобы они могли быть сериализованы для таких целей, как передача их через домены приложения.
11

В нашем текущем проекте мы используем

[ComVisible(false)]

Он контролирует доступ отдельного управляемого типа или члена или всех типов внутри сборки к COM.

Дополнительная информация

11
[TypeConverter(typeof(ExpandableObjectConverter))]

Сообщает разработчику развернуть свойства, которые являются классами (вашего контроля)

[Obfuscation]

Указывает инструменты обфускации для выполнения указанных действий для сборки, типа или члена. (Обычно вы используете уровень сборки [assembly:ObfuscateAssemblyAttribute(true)]

  • 1
    Я угадал, но был неправ. Атрибут Obfuscation - это только подсказка для сторонних obfsucators. Это не заставляет компилятор ничего запутывать по умолчанию.
  • 0
    @DanNeely бесплатно для пользователей Visual Studio Pro / Ultimate!
Показать ещё 2 комментария
8

Атрибутами, которые я использую больше всего, являются те, которые связаны с сериализацией XML.

XmlRoot

XmlElement

XmlAttribute

и т.д...

Чрезвычайно полезно при выполнении быстрого и грязного анализа или сериализации XML.

8

Будучи разработчиком среднего уровня, мне нравится

System.ComponentModel.EditorBrowsableAttribute Позволяет мне скрывать свойства, чтобы разработчик пользовательского интерфейса не был перегружен свойствами, которые им не нужно видеть.

System.ComponentModel.BindableAttribute Некоторые вещи не обязательно должны быть привязаны к базе данных. Опять же, уменьшает работу разработчиков UI.

Мне также нравится DefaultValue, о котором говорил Лоуренс Джонстон.

System.ComponentModel.BrowsableAttribute и Flags используются регулярно.

Я использую System.STAThreadAttribute System.ThreadStaticAttribute при необходимости.

Кстати. Я так же ценен для всех разработчиков .Net framework.

7

[EditorBrowsable(EditorBrowsableState.Never)] позволяет скрывать свойства и методы от IntelliSense, если проект отсутствует в вашем решении. Очень полезно скрывать недопустимые потоки для свободного интерфейса. Как часто вы хотите использовать GetHashCode() или Equals()?

Для MVC [ActionName("Name")] вы можете иметь действие "Действие" и "Действие" с той же сигнатурой метода или использовать тире в имени действия, что в противном случае было бы невозможным без создания маршрута для него.

7

Сверху моей головы, вот быстрый список, грубо отсортированный по частоте использования, предопределенных атрибутов, которые я фактически использую в большом проекте (~ 500k LoCs):

Флаги, Serializable, WebMethod, COMVisible, TypeConverter, Условные, ThreadStatic, Устаревшие, InternalsVisibleTo, DebuggerStepThrough.

  • 2
    +1 для ThreadStatic, удивило, что никто не упомянул это до сих пор, а также для статистического подхода
6

Я считаю, что здесь важно отметить, что также важны следующие атрибуты:

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;
}
  • 0
    Используется ли STAThread для предотвращения случайного вращения вашего приложения при запуске другого экземпляра?
6

[DeploymentItem("myFile1.txt")] MSDN Doc в DeploymentItem

Это действительно полезно, если вы тестируете файл или используете файл в качестве входа в свой тест.

5

Я генерирую класс сущности данных через 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;
    }
}
}
5

[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() { }
}
2

Я всегда использую атрибуты, [Serializable], [WebMethod], [DefaultValue], [Description("description here")].

но помимо этого есть Глобальные атрибуты в С#.

[assembly: System.CLSCompliant(true)]
[assembly: AssemblyCulture("")]
[assembly: AssemblyDescription("")]
2
// on configuration sections
[ConfigurationProperty] 

// in asp.net
[NotifyParentProperty(true)]
  • 3
    Какова цель NotifyParentProperty ?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню