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 associez à 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 fournissent des informations qui peuvent être lues lors 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 à l’aide de 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 et des propriétés, puis les invoquer dynamiquement :

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

Les attributs et la réflexion alimentent 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 automatiquement les services.

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. Cela ressemble à la façon dont les frameworks réels découvrent les composants, les méthodes de test ou les points de terminaison d’API lors de l’exécution.

Vous organiserez votre code dans trois fichiers :

  • PluginAttribute.cs : créez un attribut personnalisé appelé PluginAttribute dans l’espace de noms PluginSystem. Votre attribut doit :
    • Hériter de Attribute
    • Posséder 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ée avec [Plugin("Image Processor", "1.0")]
    • DataExporter - marquée avec [Plugin("Data Exporter", "2.5")]
    • HelperUtility - NON marquée avec un attribut (il s’agit simplement d’une classe ordinaire)
    Chaque classe peut être vide : nous nous intéressons uniquement à 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 :
    • Obtenir tous les types de l’assembly actuel
    • Vérifier si chaque type possède le 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 véritables 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 suivant : ImageProcessor en premier, puis DataExporter. La classe HelperUtility ne doit pas apparaître dans la sortie puisqu’elle ne possède pas l’attribut.

Sortie attendue :

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

Ce défi montre comment les frameworks utilisent les attributs comme marqueurs et la réflexion pour les découvrir - c’est la même technique qui permet le fonctionnement des conteneurs d’injection de dépendances, des bibliothèques de sérialisation et des frameworks de test !

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
        // Indice : Utilisez Assembly.GetExecutingAssembly().GetTypes()
        
        // TODO: Parcourir chaque type et vérifier s'il a le PluginAttribute
        // Indice : Utilisez type.GetCustomAttribute<PluginAttribute>()
        
        // TODO: Si l'attribut existe, afficher les infos 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

Entraînez-vous par vous-même : Compilateur C# en ligne