Menu
Coddy logo textTech

Attributs et Réflexion

Fait partie de la section Programmation Orientée Objet du Journey C# de Coddy — leçon 44 sur 70.

Les attributs sont des balises de métadonnées que vous attachez à des éléments de code tels que des classes, des méthodes ou des propriétés. Ils ne modifient pas directement la manière dont le code s'exécute, mais ils fournissent des informations qui peuvent être lues au moment de l'exécution. La réflexion est le mécanisme qui lit ces métadonnées.

Vous appliquez un attribut en le plaçant entre crochets au-dessus de l'élément cible :

[Obsolete("Use NewMethod instead")]
public void OldMethod() { }

[Serializable]
public class Person
{
    public string Name { get; set; }
}

Vous pouvez créer des attributs personnalisés en héritant de Attribute :

public class AuthorAttribute : Attribute
{
    public string Name { get; }
    public AuthorAttribute(string name) => Name = name;
}

[Author("John")]
public class Calculator { }

La réflexion vous permet d'inspecter les types et de lire les attributs au moment de l'exécution en utilisant l'espace de noms System.Reflection :

Type type = typeof(Calculator);
var attr = type.GetCustomAttribute<AuthorAttribute>();
Console.WriteLine(attr.Name);  // John

Vous pouvez également découvrir des méthodes, des propriétés et les invoquer dynamiquement :

MethodInfo[] methods = type.GetMethods();
foreach (var method in methods)
    Console.WriteLine(method.Name);

Les attributs et la réflexion propulsent de nombreux frameworks : les bibliothèques de sérialisation les utilisent pour contrôler la sortie JSON, les frameworks de test les utilisent pour découvrir les méthodes de test, et les conteneurs d'injection de dépendances les utilisent pour connecter les services automatiquement.

challenge icon

Défi

Facile

Construisons un système de découverte de plugins qui utilise des attributs personnalisés et la réflexion pour trouver et décrire automatiquement les classes marquées comme plugins. C'est ainsi que les frameworks réels découvrent des composants, des méthodes de test ou des points de terminaison d'API au moment de l'exécution.

Vous organiserez votre code sur trois fichiers :

  • PluginAttribute.cs : Créez un attribut personnalisé appelé PluginAttribute dans l'espace de noms PluginSystem. Votre attribut doit :
    • Hériter de Attribute
    • Avoir deux propriétés en lecture seule : Name (string) et Version (string)
    • Accepter les deux valeurs via son constructeur
  • Plugins.cs : Créez plusieurs classes de plugins dans l'espace de noms PluginSystem. Certaines doivent être décorées avec votre PluginAttribute, et une ne doit pas l'être :
    • ImageProcessor - marqué avec [Plugin("Image Processor", "1.0")]
    • DataExporter - marqué avec [Plugin("Data Exporter", "2.5")]
    • HelperUtility - NON marqué par aucun attribut (c'est juste une classe ordinaire)
    Chaque classe peut être vide - nous sommes seulement intéressés par la découverte de leurs métadonnées via la réflexion.
  • Program.cs : Dans votre fichier principal, utilisez la réflexion pour découvrir toutes les classes qui possèdent le PluginAttribute. Pour chaque plugin découvert, affichez ses informations. Vous devrez :
    • Récupérer tous les types de l'assembly actuel
    • Vérifier chaque type pour la présence du PluginAttribute
    • Extraire et afficher les propriétés Name et Version de l'attribut

Utilisez System.Reflection pour inspecter les types et récupérer les attributs personnalisés. La méthode GetCustomAttribute<T>() renvoie null si l'attribut n'est pas présent, vous pouvez donc l'utiliser pour filtrer les classes qui sont de réels plugins.

Affichez chaque plugin découvert dans ce format, un par ligne :

Plugin: {Name} (v{Version})

Les plugins doivent être affichés dans l'ordre : ImageProcessor en premier, puis DataExporter. La classe HelperUtility ne doit pas apparaître dans la sortie car elle n'a pas l'attribut.

Sortie attendue :

Plugin: Image Processor (v1.0)
Plugin: Data Exporter (v2.5)

Ce défi démontre comment les frameworks utilisent les attributs comme marqueurs et la réflexion pour les découvrir - la même technique alimente les conteneurs d'injection de dépendances, les bibliothèques de sérialisation et les frameworks de test !

Aide-mémoire

Les attributs sont des balises de métadonnées placées entre crochets au-dessus des éléments de code. Ils fournissent des informations qui peuvent être lues au moment de l'exécution :

[Obsolete("Use NewMethod instead")]
public void OldMethod() { }

[Serializable]
public class Person
{
    public string Name { get; set; }
}

Créez des attributs personnalisés en héritant de Attribute :

public class AuthorAttribute : Attribute
{
    public string Name { get; }
    public AuthorAttribute(string name) => Name = name;
}

[Author("John")]
public class Calculator { }

La réflexion vous permet d'inspecter les types et de lire les attributs au moment de l'exécution en utilisant l'espace de noms System.Reflection :

Type type = typeof(Calculator);
var attr = type.GetCustomAttribute<AuthorAttribute>();
Console.WriteLine(attr.Name);  // John

Découvrez les méthodes et les propriétés de manière dynamique :

MethodInfo[] methods = type.GetMethods();
foreach (var method in methods)
    Console.WriteLine(method.Name);

La méthode GetCustomAttribute<T>() renvoie null si l'attribut n'est pas présent, ce qui vous permet de filtrer les types en fonction de la présence de l'attribut.

Essayez vous-même

using System;
using System.Reflection;
using PluginSystem;

class Program
{
    public static void Main(string[] args)
    {
        // TODO: Obtenir tous les types de l'assembly actuel
        // Astuce : Utilisez Assembly.GetExecutingAssembly().GetTypes()
        
        // TODO: Parcourir chaque type et vérifier s'il possède l'attribut PluginAttribute
        // Astuce : Utilisez type.GetCustomAttribute<PluginAttribute>()
        
        // TODO: Si l'attribut existe, afficher les informations du plugin au format :
        // Plugin: {Name} (v{Version})
        
    }
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation Orientée Objet