Ricerca…


Creare un attributo personalizzato

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

Utilizzando un attributo

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

Leggere un attributo

Metodo GetCustomAttributes restituisce una serie di attributi personalizzati applicati al membro. Dopo aver recuperato questo array è possibile cercare uno o più attributi specifici.

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

Oppure scorrere attraverso di loro

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

GetCustomAttribute metodo di estensione GetCustomAttribute di System.Reflection.CustomAttributeExtensions recupera un attributo personalizzato di un tipo specificato, può essere applicato a qualsiasi MemberInfo .

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

GetCustomAttribute ha anche una firma generica per specificare il tipo di attributo da cercare.

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

L'argomento Boolean inherit può essere passato ad entrambi questi metodi. Se questo valore è impostato su true gli antenati dell'elemento dovrebbero essere esaminati.

DebuggerDisplay Attribute

Aggiungere l'attributo DebuggerDisplay cambierà il modo in cui il debugger visualizza la classe quando viene posizionata al passaggio del mouse.

Le espressioni racchiuse in {} verranno valutate dal debugger. Può trattarsi di una proprietà semplice come nell'esempio seguente o in una logica più complessa.

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

Esempio di DebuggerDisplay

Aggiungendo ,nq prima della parentesi di chiusura rimuove le virgolette quando si stampa una stringa.

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

Anche se le espressioni generali sono consentite in {} non sono raccomandate. L'attributo DebuggerDisplay verrà scritto nei metadati dell'assieme sotto forma di stringa. Le espressioni in {} non vengono verificate per la validità. Quindi un attributo DebuggerDisplay contenente una logica più complessa di una semplice aritmetica potrebbe funzionare bene in C #, ma la stessa espressione valutata in VB.NET probabilmente non sarà sintatticamente valida e produrrà un errore durante il debug.

Un modo per rendere DebuggerDisplay più indipendente dalla lingua è scrivere l'espressione in un metodo o in una proprietà e chiamarla invece.

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

Si potrebbe desiderare che DebuggerDisplay restituisca tutte o solo alcune proprietà e durante il debug e l'ispezione del tipo dell'oggetto.
L'esempio seguente circonda anche il metodo helper con #if DEBUG dato che DebuggerDisplay viene utilizzato negli ambienti di debug.

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

Attributi di informazioni sul chiamante

Gli attributi di informazioni sul chiamante possono essere utilizzati per trasmettere informazioni sull'invocatore al metodo richiamato. La dichiarazione assomiglia a questo:

using System.Runtime.CompilerServices;

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

E l'invocazione assomiglia a questo:

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

Si noti che solo il primo parametro viene passato esplicitamente al metodo LogException mentre il resto di essi verrà fornito in fase di compilazione con i valori pertinenti.

Il parametro callerMemberName riceverà il valore "Save" , il nome del metodo di chiamata.

Il parametro callerLineNumber riceverà il numero di qualsiasi riga su LogException è scritta la chiamata del metodo LogException .

E il parametro 'callerFilePath' riceverà il percorso completo del file in cui è stato dichiarato il metodo Save .

Lettura di un attributo dall'interfaccia

Non esiste un modo semplice per ottenere attributi da un'interfaccia, poiché le classi non ereditano gli attributi da un'interfaccia. Ogni volta che si implementa un'interfaccia o si sovrascrivono i membri in una classe derivata, è necessario dichiarare nuovamente gli attributi. Quindi nell'esempio seguente l'output sarebbe True in tutti e tre i casi.

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

Un modo per recuperare gli attributi dell'interfaccia è cercarli attraverso tutte le interfacce implementate da una classe.

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

Attributo obsoleto

System.Obsolete è un attributo che viene utilizzato per contrassegnare un tipo o un membro che ha una versione migliore e pertanto non deve essere utilizzato.

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

Nel caso in cui la classe sopra sia usata, il compilatore darà l'avvertimento "Questa classe è obsoleta. Usa SomeOtherClass invece."



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow