Szukaj…


Tworzenie niestandardowego atrybutu

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

Korzystanie z atrybutu

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

Odczytywanie atrybutu

Metoda GetCustomAttributes zwraca tablicę niestandardowych atrybutów zastosowanych do elementu członkowskiego. Po pobraniu tej tablicy możesz wyszukać jeden lub więcej określonych atrybutów.

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

Lub iteruj przez nie

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

Metoda rozszerzenia GetCustomAttribute z System.Reflection.CustomAttributeExtensions pobiera niestandardowy atrybut określonego typu, można go zastosować do dowolnego MemberInfo .

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

GetCustomAttribute ma również podpis ogólny, który określa typ atrybutu do wyszukania.

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

inherit argumentu logicznego można przekazać do obu tych metod. Jeśli ta wartość jest ustawiona na true przodkowie elementu również będą sprawdzani.

DebuggerDisplay Atrybut

Dodanie atrybutu DebuggerDisplay zmieni sposób, w jaki debugger wyświetla klasę po najechaniu kursorem.

Wyrażenia opakowane w {} zostaną ocenione przez debugger. Może to być prosta właściwość, jak w poniższym przykładzie lub bardziej złożona logika.

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

Przykład DebuggerDisplay

Dodanie ,nq przed nawiasem zamykającym usuwa cudzysłowy podczas wyprowadzania łańcucha.

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

Mimo że wyrażenia ogólne są dozwolone w {} nie są zalecane. Atrybut DebuggerDisplay zostanie zapisany w metadanych zestawu jako ciąg. Wyrażenia w {} nie są sprawdzane pod kątem ważności. Zatem atrybut DebuggerDisplay zawierający bardziej złożoną logikę niż np. Jakaś prosta arytmetyka może działać dobrze w języku C #, ale to samo wyrażenie ocenione w VB.NET prawdopodobnie nie będzie poprawne pod względem składniowym i spowoduje błąd podczas debugowania.

Sposobem na uczynienie DebuggerDisplay bardziej DebuggerDisplay od języka jest napisanie wyrażenia w metodzie lub właściwości i wywołanie go zamiast tego.

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

Można chcieć, aby DebuggerDisplay wyświetlał wszystkie lub tylko niektóre właściwości, a podczas debugowania i sprawdzania także typu obiektu.
Poniższy przykład otacza również metodę pomocniczą #if DEBUG ponieważ DebuggerDisplay jest używany w środowiskach debugujących.

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

Atrybuty informacji o dzwoniącym

Atrybuty informacji o abonencie wywołującym można wykorzystać do przekazania informacji o wywoływaczu do wywoływanej metody. Deklaracja wygląda następująco:

using System.Runtime.CompilerServices;

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

I wywołanie wygląda następująco:

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

Zauważ, że tylko pierwszy parametr jest jawnie przekazywany do metody LogException , podczas gdy reszta zostanie dostarczona w czasie kompilacji z odpowiednimi wartościami.

Parametr callerMemberName otrzyma wartość "Save" - nazwę metody wywołującej.

Parametr callerLineNumber otrzyma numer linii, na LogException zapisywane jest wywołanie metody LogException .

A parametr „callerFilePath” otrzyma pełną ścieżkę do pliku, w którym zapisana jest metoda Save .

Odczytywanie atrybutu z interfejsu

Nie ma prostego sposobu uzyskania atrybutów z interfejsu, ponieważ klasy nie dziedziczą atrybutów z interfejsu. Za każdym razem, gdy implementujesz interfejs lub zastępujesz elementy w klasie pochodnej, musisz ponownie zadeklarować atrybuty. Zatem w poniższym przykładzie dane wyjściowe byłyby True we wszystkich trzech przypadkach.

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

Jednym ze sposobów pobierania atrybutów interfejsu jest wyszukiwanie ich przez wszystkie interfejsy zaimplementowane przez klasę.

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

Przestarzały atrybut

System.Obsolete jest atrybutem używanym do oznaczania typu lub elementu, który ma lepszą wersję i dlatego nie powinien być używany.

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

W przypadku użycia powyższej klasy kompilator wyświetli ostrzeżenie „Ta klasa jest przestarzała. Zamiast tego użyj SomeOtherClass”.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow