Как создать пользовательский атрибут в С#

Я пробовал много раз, но все же я не могу понять использование пользовательских атрибутов (я уже прошел через множество ссылок).

Может кто-нибудь объяснить мне очень простой пример пользовательского атрибута с кодом?

Ответ 1

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

Атрибуты - это метаданные, скомпилированные в вашей программе. Сами атрибуты не добавляют никакой функциональности к классу, свойству или модулю - только данные. Однако, используя отражение, можно использовать эти атрибуты для создания функциональности.

Так, например, давайте посмотрим на Блок приложения проверки из Microsoft Enterprise Library. Если вы посмотрите на пример кода, вы увидите:

    /// <summary>
    /// blah blah code.
    /// </summary>
    [DataMember]
    [StringLengthValidator(8, RangeBoundaryType.Inclusive, 8, RangeBoundaryType.Inclusive, MessageTemplate = "\"{1}\" must always have \"{4}\" characters.")]
    public string Code { get; set; }

Из приведенного выше фрагмента можно предположить, что код всегда будет проверяться при каждом изменении в соответствии с правилами Валидатора (в данном примере не менее 8 символов и не более 8 символов). Но правда в том, что Атрибут ничего не делает; как упоминалось ранее, он добавляет метаданные только к свойству.

Однако в Enterprise Library есть метод Validation.Validate, который проверяет ваш объект, и для каждого свойства он проверяет, нарушает ли содержимое правило, сообщаемое атрибутом.

Таким образом, вот как вы должны думать об атрибутах - способ добавить данные в ваш код, которые впоследствии могут быть использованы другими методами/классами/и т.д.

Ответ 2

Вы начинаете с написания класса, который происходит от Attribute:

public class MyCustomAttribute: Attribute
{
    public string SomeProperty { get; set; }
}

Затем вы можете украсить все (класс, метод, свойство,...) с помощью этого атрибута:

[MyCustomAttribute(SomeProperty = "foo bar")]
public class Foo
{

}

и, наконец, вы будете использовать отражение для его получения:

var customAttributes = (MyCustomAttribute[])typeof(Foo).GetCustomAttributes(typeof(MyCustomAttribute), true);
if (customAttributes.Length > 0)
{
    var myAttribute = customAttributes[0];
    string value = myAttribute.SomeProperty;
    // TODO: Do something with the value
}

Вы можете ограничить целевые типы, к которым этот пользовательский атрибут может быть применен, используя атрибут AttributeUsage:

/// <summary>
/// This attribute can only be applied to classes
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class MyCustomAttribute : Attribute

Важные сведения об атрибутах:

  • Атрибуты - это метаданные.
  • Они запекаются в сборку в время компиляции, что имеет очень серьезные последствия того, как вы можете установить свои свойства. Принимаются только значения константы (известные во время компиляции).
  • Единственный способ использовать смысл и использование пользовательских атрибутов - использовать Reflection. Поэтому, если вы не используете отражение во время выполнения, чтобы получить их и украсить что-то с помощью настраиваемого атрибута, не ожидайте, что многое произойдет.
  • Время создания атрибутов не является детерминированным. Они создаются в среде CLR, и у вас нет абсолютно никакого контроля над ней.

Ответ 3

Использование/Копирование Дарин Димитров отличный ответ, вот как получить доступ к настраиваемому атрибуту свойства, а не к классу:

Украшенное свойство [класса Foo]:

[MyCustomAttribute(SomeProperty = "This is a custom property")]
public string MyProperty { get; set; }

Извлечение:

PropertyInfo propertyInfo = typeof(Foo).GetProperty(propertyToCheck);
object[] attribute = propertyInfo.GetCustomAttributes(typeof(MyCustomAttribute), true);
if (attribute.Length > 0)
{
    MyCustomAttribute myAttribute = (MyCustomAttribute)attribute[0];
    string propertyValue = myAttribute.SomeProperty;
}

Вы можете бросить это в цикле и использовать отражение для доступа к этому настраиваемому атрибуту для каждого свойства класса Foo:

foreach (PropertyInfo propertyInfo in Foo.GetType().GetProperties())
{
    string propertyName = propertyInfo.Name;

    object[] attribute = propertyInfo.GetCustomAttributes(typeof(MyCustomAttribute), true);
    // Just in case you have a property without this annotation
    if (attribute.Length > 0)
    {
        MyCustomAttribute myAttribute = (MyCustomAttribute)attribute[0];
        string propertyValue = myAttribute.SomeProperty;
        // TODO: whatever you need with this propertyValue
    }
}

Большое спасибо вам, Дарин!