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

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

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

Ответ 1

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

Ответ 2

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

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

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

Ответ 3

[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 указывает на то, чего я не осознал, и который скорее ослабит мой энтузиазм по этому атрибуту: он не инструктирует компилятор разрешить битовые комбинации как допустимые значения для переменных перечисления компилятор допускает это для перечислений независимо. Мой фон С++ показывает... вздох

Ответ 4

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

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

Ответ 5

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

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

Ответ 6

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

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

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

Ответ 7

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

Ответ 8

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

Ответ 9

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

Ответ 10

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

Ответ 11

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

Ответ 12

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

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

Ответ 13

[XmlIgnore]

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

Ответ 14

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

Ответ 15

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

[ImmutableObject(true)]

Ответ 16

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

[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public Foo Bar {
    get { return baz; }
    set { baz = value; }
}

Ответ 17

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

Ответ 18

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

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

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

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

Ответ 19

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

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

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

Ответ 20

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

 [Serializable]
 [WebMethod]

Ответ 21

[TypeConverter(typeof(ExpandableObjectConverter))]

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

[Obfuscation]

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

Ответ 22

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

[ComVisible(false)]

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

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

Ответ 23

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

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

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

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

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

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

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

Ответ 24

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

XmlRoot

XmlElement

XmlAttribute

и т.д...

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

Ответ 25

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

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

Ответ 26

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

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

Ответ 27

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

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

Ответ 28

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

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;
}

Ответ 29

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

Ответ 30

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