Menu
Coddy logo textTech

Atrybuty i refleksja

Część sekcji Programowanie obiektowe ścieżki C# w Coddy. Lekcja 44 z 70.

Atrybuty to znaczniki metadanych, które dołączasz do elementów kodu, takich jak klasy, metody czy właściwości. Nie zmieniają bezpośrednio sposobu wykonywania kodu, ale dostarczają informacji, które można odczytać w czasie działania programu. Refleksja to mechanizm odczytujący te metadane.

Atrybut stosujesz, umieszczając go w nawiasach kwadratowych nad elementem docelowym:

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

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

Możesz tworzyć niestandardowe atrybuty, dziedzicząc po Attribute:

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

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

Refleksja pozwala sprawdzać typy i odczytywać atrybuty w czasie wykonywania programu za pomocą przestrzeni nazw System.Reflection:

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

Możesz także odkrywać metody i właściwości oraz wywoływać je dynamicznie:

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

Atrybuty i refleksja są wykorzystywane przez wiele frameworków — biblioteki do serializacji używają ich do kontrolowania danych wyjściowych JSON, frameworki testowe do wyszukiwania metod testowych, a kontenery wstrzykiwania zależności do automatycznego łączenia usług.

challenge icon

Wyzwanie

Łatwy

Stwórzmy system wykrywania wtyczek, który używa atrybutów niestandardowych i refleksji, aby automatycznie znajdować klasy oznaczone jako wtyczki i opisywać je. Działa to podobnie do sposobu, w jaki rzeczywiste frameworki wykrywają komponenty, metody testowe lub punkty końcowe API w czasie działania programu.

Rozmieść kod w trzech plikach:

  • PluginAttribute.cs: Utwórz atrybut niestandardowy o nazwie PluginAttribute w przestrzeni nazw PluginSystem. Twój atrybut powinien:
    • Dziedziczyć po Attribute
    • Mieć dwie właściwości tylko do odczytu: Name (string) i Version (string)
    • Przyjmować obie wartości przez konstruktor
  • Plugins.cs: Utwórz kilka klas wtyczek w przestrzeni nazw PluginSystem. Niektóre powinny być ozdobione atrybutem PluginAttribute, a jedna nie:
    • ImageProcessor — oznaczona atrybutem [Plugin("Image Processor", "1.0")]
    • DataExporter — oznaczona atrybutem [Plugin("Data Exporter", "2.5")]
    • HelperUtility — NIE oznaczaj żadnym atrybutem (to zwykła klasa)
    Każda klasa może być pusta — interesuje nas tylko wykrywanie jej metadanych za pomocą refleksji.
  • Program.cs: W głównym pliku użyj refleksji, aby wykryć wszystkie klasy, które mają atrybut PluginAttribute. Dla każdej wykrytej wtyczki wypisz jej informacje. Musisz:
    • Pobrać wszystkie typy z bieżącego zestawu
    • Sprawdzić każdy typ pod kątem atrybutu PluginAttribute
    • Pobrać i wyświetlić właściwości atrybutu Name i Version

Użyj System.Reflection, aby sprawdzać typy i pobierać atrybuty niestandardowe. Metoda GetCustomAttribute<T>() zwraca null, jeśli atrybut nie jest obecny, więc możesz użyć jej do filtrowania klas będących wtyczkami.

Wypisz każdą wykrytą wtyczkę w tym formacie, po jednej w każdym wierszu:

Plugin: {Name} (v{Version})

Wtyczki powinny być wypisane w następującej kolejności: najpierw ImageProcessor, a następnie DataExporter. Klasa HelperUtility nie powinna pojawić się w wyniku, ponieważ nie ma tego atrybutu.

Oczekiwany wynik:

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

To wyzwanie pokazuje, jak frameworki używają atrybutów jako znaczników oraz refleksji do ich wykrywania — ta sama technika jest stosowana w kontenerach wstrzykiwania zależności, bibliotekach serializacji i frameworkach testowych!

Spróbuj swoich sił

using System;
using System.Reflection;
using PluginSystem;

class Program
{
    public static void Main(string[] args)
    {
        // TODO: Pobierz wszystkie typy z bieżącego zestawu
        // Wskazówka: Użyj Assembly.GetExecutingAssembly().GetTypes()
        
        // TODO: Przejdź przez każdy typ i sprawdź, czy ma atrybut PluginAttribute
        // Wskazówka: Użyj type.GetCustomAttribute<PluginAttribute>()
        
        // TODO: Jeśli atrybut istnieje, wypisz informacje o wtyczce w formacie:
        // Plugin: {Name} (v{Version})
        
    }
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator C# online