Recherche…


Création d'un attribut personnalisé

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

Utiliser un attribut

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

Lecture d'un attribut

La méthode GetCustomAttributes renvoie un tableau d'attributs personnalisés appliqués au membre. Après avoir récupéré ce tableau, vous pouvez rechercher un ou plusieurs attributs spécifiques.

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

Ou itérer à travers eux

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

GetCustomAttribute méthode d'extension GetCustomAttribute de System.Reflection.CustomAttributeExtensions extrait un attribut personnalisé d'un type spécifié, il peut être appliqué à n'importe quel MemberInfo .

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

GetCustomAttribute également une signature générique pour spécifier le type d'attribut à rechercher.

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

Argument booléen inherit peut être transmis à ces deux méthodes. Si cette valeur est définie sur true les ancêtres de l'élément seront également inspectés.

Attribut DebuggerDisplay

L'ajout de l'attribut DebuggerDisplay modifie la façon dont le débogueur affiche la classe lorsqu'il est survolé.

Les expressions enveloppées dans {} seront évaluées par le débogueur. Cela peut être une propriété simple comme dans l'exemple suivant ou une logique plus complexe.

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

Exemple DebuggerDisplay

L'ajout de ,nq avant le crochet de fermeture supprime les guillemets lors de la sortie d'une chaîne.

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

Même si les expressions générales sont autorisées dans {} elles ne sont pas recommandées. L'attribut DebuggerDisplay sera écrit dans la métadonnée de l'assemblage sous forme de chaîne. Les expressions dans {} ne sont pas vérifiées pour la validité. Ainsi, un attribut DebuggerDisplay contenant une logique plus complexe que par exemple une arithmétique simple pourrait fonctionner correctement en C #, mais la même expression évaluée dans VB.NET ne sera probablement pas syntaxiquement valide et produira une erreur lors du débogage.

Une façon de rendre DebuggerDisplay plus agnostique en DebuggerDisplay langage consiste à écrire l'expression dans une méthode ou une propriété et à l'appeler à la place.

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

On peut souhaiter que DebuggerDisplay toutes ou certaines propriétés et lors du débogage et de l'inspection du type d'objet.
L'exemple ci-dessous entoure également la méthode d'assistance avec #if DEBUG car DebuggerDisplay est utilisé dans les environnements de débogage.

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

Attributs d'information de l'appelant

Les attributs d'information de l'appelant peuvent être utilisés pour transmettre des informations sur l'invocateur à la méthode invoquée. La déclaration ressemble à ceci:

using System.Runtime.CompilerServices;

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

Et l'invocation ressemble à ceci:

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

Notez que seul le premier paramètre est passé explicitement à la méthode LogException alors que les autres seront fournis au moment de la compilation avec les valeurs appropriées.

Le paramètre callerMemberName recevra la valeur "Save" - le nom de la méthode d'appel.

Le paramètre callerLineNumber recevra le numéro de la ligne sur LogException appel de méthode LogException est écrit.

Et le paramètre 'callerFilePath' recevra le chemin complet du fichier dans lequel la méthode Save est déclarée.

Lecture d'un attribut depuis l'interface

Il n'y a pas de moyen simple d'obtenir des attributs à partir d'une interface, car les classes n'héritent pas des attributs d'une interface. Chaque fois que vous implémentez une interface ou que vous remplacez des membres dans une classe dérivée, vous devez déclarer à nouveau les attributs. Donc, dans l'exemple ci-dessous, le résultat serait True dans les trois cas.

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

Une façon de récupérer les attributs d'interface consiste à les rechercher via toutes les interfaces implémentées par une 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

Attribut obsolète

System.Obsolete est un attribut utilisé pour marquer un type ou un membre qui a une meilleure version et ne doit donc pas être utilisé.

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

Si la classe ci-dessus est utilisée, le compilateur affichera l'avertissement "Cette classe est obsolète. Utilisez plutôt SomeOtherClass".



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow