Поиск…


Создание настраиваемого атрибута

//1) All attributes should be inherited from System.Attribute
//2) You can customize your attribute usage (e.g. place restrictions) by using System.AttributeUsage Attribute
//3) You can use this attribute only via reflection in the way it is supposed to be used
//4) MethodMetadataAttribute is just a name. You can use it without "Attribute" postfix - e.g. [MethodMetadata("This text could be retrieved via reflection")].
//5) You can overload an attribute constructors
[System.AttributeUsage(System.AttributeTargets.Method | System.AttributeTargets.Class)]
public class MethodMetadataAttribute : System.Attribute
{
    //this is custom field given just for an example
    //you can create attribute without any fields
    //even an empty attribute can be used - as marker
    public string Text { get; set; }

    //this constructor could be used as [MethodMetadata]
    public MethodMetadataAttribute ()
    {
    }

    //This constructor could be used as [MethodMetadata("String")]
    public MethodMetadataAttribute (string text)
    {
        Text = text;
    }
}

Использование атрибута

[StackDemo(Text = "Hello, World!")]
public class MyClass
{
    [StackDemo("Hello, World!")]
    static void MyMethod()
    {
    }
}

Чтение атрибута

Метод GetCustomAttributes возвращает массив пользовательских атрибутов, применяемых к элементу. После извлечения этого массива вы можете искать один или несколько конкретных атрибутов.

var attribute = typeof(MyClass).GetCustomAttributes().OfType<MyCustomAttribute>().Single();

Или итерации через них

foreach(var attribute in typeof(MyClass).GetCustomAttributes()) {
    Console.WriteLine(attribute.GetType());
}

GetCustomAttribute расширения GetCustomAttribute из System.Reflection.CustomAttributeExtensions извлекает пользовательский атрибут указанного типа, его можно применить к любому MemberInfo .

var attribute = (MyCustomAttribute) typeof(MyClass).GetCustomAttribute(typeof(MyCustomAttribute));

GetCustomAttribute также имеет общую подпись для указания типа атрибута для поиска.

var attribute = typeof(MyClass).GetCustomAttribute<MyCustomAttribute>();

inherit логических аргументов может быть передано обоим этим методам. Если для этого значения установлено значение true предки элемента также будут проверяться.

Атрибут DebuggerDisplay

Добавление атрибута DebuggerDisplay изменит способ отображения класса отладчика при его зависании.

Выражения, которые завернуты в {} будут оцениваться отладчиком. Это может быть простое свойство, как в следующем примере или более сложной логике.

[DebuggerDisplay("{StringProperty} - {IntProperty}")]
public class AnObject
{
   public int ObjectId { get; set; }
   public string StringProperty { get; set; }
   public int IntProperty { get; set; }
}

Пример отладчикаDisplay

Добавляя ,nq перед закрывающей скобкой удаляет кавычки при выводе строки.

[DebuggerDisplay("{StringProperty,nq} - {IntProperty}")]

Даже если общие выражения разрешены в {} они не рекомендуются. Атрибут DebuggerDisplay будет записан в метаданные сборки как строку. Выражения в {} не проверяются на достоверность. Таким образом, атрибут DebuggerDisplay содержащий более сложную логику, чем простая простая арифметика, может отлично работать на C #, но одно и то же выражение, оцениваемое в VB.NET, вероятно, не будет синтаксически корректным и приведет к ошибке при отладке.

Способ сделать DebuggerDisplay более агностиком языка - написать выражение в методе или свойстве и вызвать его вместо этого.

[DebuggerDisplay("{DebuggerDisplay(),nq}")]
public class AnObject
{
   public int ObjectId { get; set; }
   public string StringProperty { get; set; }
   public int IntProperty { get; set; }

   private string DebuggerDisplay()
    {
        return $"{StringProperty} - {IntProperty}"";
    }
}

Возможно, DebuggerDisplay может выводить все или только некоторые из свойств, а также при отладке и проверке типа объекта.
Пример ниже также окружает вспомогательный метод с #if DEBUG поскольку DebuggerDisplay используется в средах отладки.

[DebuggerDisplay("{DebuggerDisplay(),nq}")]
public class AnObject
{
   public int ObjectId { get; set; }
   public string StringProperty { get; set; }
   public int IntProperty { get; set; }

#if DEBUG
   private string DebuggerDisplay()
    {
        return
            $"ObjectId:{this.ObjectId}, StringProperty:{this.StringProperty}, Type:{this.GetType()}";
    }
    #endif
}

Атрибуты информации об абоненте

Атрибуты информации о вызывающем абоненте могут использоваться для передачи информации о вызове вызываемому методу. Декларация выглядит так:

using System.Runtime.CompilerServices;

public void LogException(Exception ex,
                         [CallerMemberName]string callerMemberName = "",
                         [CallerLineNumber]int callerLineNumber = 0,
                         [CallerFilePath]string callerFilePath = "")
{
    //perform logging
}

И вызов выглядит так:

public void Save(DBContext context)
{
    try
    {
        context.SaveChanges();
    }
    catch (Exception ex)
    {
        LogException(ex);
    }
}

Обратите внимание, что только первый параметр передается явно методу LogException тогда как остальные из них будут предоставлены во время компиляции соответствующими значениями.

Параметр callerMemberName получит значение "Save" - имя вызывающего метода.

Параметр callerLineNumber будет получать количество строк, на которые LogException вызов метода LogException .

И параметр 'callerFilePath' получит полный путь к файлу. Объявлен метод Save .

Чтение атрибута из интерфейса

Нет простого способа получить атрибуты из интерфейса, поскольку классы не наследуют атрибуты от интерфейса. Всякий раз, когда вы выполняете интерфейс или переопределяете члены производного класса, вам нужно повторно объявить атрибуты. Таким образом, в приведенном ниже примере вывод будет True во всех трех случаях.

using System;
using System.Linq;
using System.Reflection;

namespace InterfaceAttributesDemo {
    
    [AttributeUsage(AttributeTargets.Interface, Inherited = true)]
    class MyCustomAttribute : Attribute {
        public string Text { get; set; }
    }
    
    [MyCustomAttribute(Text = "Hello from interface attribute")]
    interface IMyClass {
        void MyMethod();
    }
    
    class MyClass : IMyClass {
        public void MyMethod() { }
    }
    
    public class Program {
        public static void Main(string[] args) {
            GetInterfaceAttributeDemo();
        }
        
        private static void GetInterfaceAttributeDemo() {
            var attribute1 = (MyCustomAttribute) typeof(MyClass).GetCustomAttribute(typeof(MyCustomAttribute), true);
            Console.WriteLine(attribute1 == null); // True
            
            var attribute2 = typeof(MyClass).GetCustomAttributes(true).OfType<MyCustomAttribute>().SingleOrDefault();
            Console.WriteLine(attribute2 == null); // True
            
            var attribute3 = typeof(MyClass).GetCustomAttribute<MyCustomAttribute>(true);
            Console.WriteLine(attribute3 == null); // True
        }
    }
}

Одним из способов получения атрибутов интерфейса является поиск их через все интерфейсы, реализованные классом.

var attribute = typeof(MyClass).GetInterfaces().SelectMany(x => x.GetCustomAttributes().OfType<MyCustomAttribute>()).SingleOrDefault();
Console.WriteLine(attribute == null); // False
Console.WriteLine(attribute.Text); // Hello from interface attribute

Устаревший атрибут

System.Obsolete - это атрибут, который используется для обозначения типа или члена, который имеет лучшую версию и, следовательно, не должен использоваться.

[Obsolete("This class is obsolete. Use SomeOtherClass instead.")]
class SomeClass
{
    //
}

В случае использования класса выше компилятор выдаст предупреждение «Этот класс устарел. Вместо этого используйте SomeOtherClass».



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow