Attributi e reflection
Fa parte della sezione Programmazione orientata agli oggetti del percorso C# di Coddy. Lezione 44 di 70.
Gli attributi sono tag di metadati che associ a elementi del codice come classi, metodi o proprietà. Non modificano direttamente il modo in cui viene eseguito il codice, ma forniscono informazioni che possono essere lette in fase di esecuzione. La reflection è il meccanismo che legge questi metadati.
Applichi un attributo inserendolo tra parentesi quadre sopra l'elemento di destinazione:
[Obsolete("Use NewMethod instead")]
public void OldMethod() { }
[Serializable]
public class Person
{
public string Name { get; set; }
}Puoi creare attributi personalizzati ereditando da Attribute:
public class AuthorAttribute : Attribute
{
public string Name { get; }
public AuthorAttribute(string name) => Name = name;
}
[Author("John")]
public class Calculator { }La riflessione ti permette di ispezionare i tipi e leggere gli attributi in fase di esecuzione usando lo spazio dei nomi System.Reflection:
Type type = typeof(Calculator);
var attr = type.GetCustomAttribute<AuthorAttribute>();
Console.WriteLine(attr.Name); // JohnPuoi anche individuare metodi e proprietà e invocarli dinamicamente:
MethodInfo[] methods = type.GetMethods();
foreach (var method in methods)
Console.WriteLine(method.Name);Gli attributi e la reflection sono alla base di molti framework: le librerie di serializzazione li usano per controllare l'output JSON, i framework di testing li usano per individuare i metodi di test e i container per l'iniezione delle dipendenze li usano per collegare automaticamente i servizi.
Sfida
FacileCreiamo un sistema di rilevamento dei plugin che usa attributi personalizzati e la reflection per trovare e descrivere automaticamente le classi contrassegnate come plugin. È simile al modo in cui i framework reali rilevano componenti, metodi di test o endpoint API in fase di esecuzione.
Organizzerai il codice in tre file:
PluginAttribute.cs: crea un attributo personalizzato chiamatoPluginAttributenello spazio dei nomiPluginSystem. Il tuo attributo deve:- Ereditare da
Attribute - Avere due proprietà di sola lettura:
Name(string) eVersion(string) - Accettare entrambi i valori tramite il costruttore
- Ereditare da
Plugins.cs: crea diverse classi di plugin nello spazio dei nomiPluginSystem. Alcune devono essere decorate con il tuoPluginAttribute, mentre una non deve esserlo:ImageProcessor- contrassegnata con[Plugin("Image Processor", "1.0")]DataExporter- contrassegnata con[Plugin("Data Exporter", "2.5")]HelperUtility- NON contrassegnata con alcun attributo (è solo una classe normale)
Program.cs: nel file principale, usa la reflection per individuare tutte le classi che hanno l'attributoPluginAttribute. Per ogni plugin individuato, stampa le sue informazioni. Dovrai:- Ottenere tutti i tipi dall'assembly corrente
- Verificare la presenza di
PluginAttributesu ogni tipo - Estrarre e mostrare le proprietà
NameeVersiondell'attributo
Usa System.Reflection per ispezionare i tipi e recuperare gli attributi personalizzati. Il metodo GetCustomAttribute<T>() restituisce null se l'attributo non è presente, quindi puoi usarlo per filtrare le classi che sono effettivamente plugin.
Stampa ogni plugin individuato in questo formato, uno per riga:
Plugin: {Name} (v{Version})I plugin devono essere stampati in questo ordine: prima ImageProcessor, poi DataExporter. La classe HelperUtility non deve comparire nell'output perché non ha l'attributo.
Output previsto:
Plugin: Image Processor (v1.0)
Plugin: Data Exporter (v2.5)Questa sfida mostra come i framework usano gli attributi come marcatori e la reflection per individuarli: la stessa tecnica è alla base dei container di dependency injection, delle librerie di serializzazione e dei framework di test!
Provalo tu
using System;
using System.Reflection;
using PluginSystem;
class Program
{
public static void Main(string[] args)
{
// TODO: Ottieni tutti i tipi dall'assembly corrente
// Suggerimento: usa Assembly.GetExecutingAssembly().GetTypes()
// TODO: Scorri ogni tipo e verifica se ha il PluginAttribute
// Suggerimento: usa type.GetCustomAttribute<PluginAttribute>()
// TODO: Se l'attributo esiste, stampa le informazioni del plugin nel formato:
// Plugin: {Name} (v{Version})
}
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti della programmazione orientata agli oggetti
File esterniNamespace e direttiveIntroduzione a classi e oggettiLa parola chiave "this"Metodi e parametriCampi e proprietàCostruttoriInizializzatori di oggettiRiepilogo - Calcolatrice semplice4Ereditarietà
Sintassi di base dell'ereditarietà (:)La parola chiave 'base'Parole chiave virtual e overrideClassi sealedLa classe base 'object'Riepilogo - Gerarchia dei dipendenti7Funzionalità avanzate
Sovraccarico degli operatoriIndicizzatori (this[])Override di ToString()Metodi di estensioneRiepilogo - Lista personalizzata10Pattern di progettazione Parte 1
Introduzione ai pattern di progettazioneSingleton thread-safePattern FactoryPattern Observer (eventi)Pattern Strategy2Proprietà e membri statici
Proprietà implementate automaticamenteProprietà di sola lettura e di sola scritturaCampi e metodi staticiClassi staticheMembri con corpo di espressione5Polimorfismo e interfacce
Polimorfismo a compile time e runtimeInterfaccia o classe astrattaInterfacce multipleInterfacce espliciteUpcasting e downcastingRipasso: calcolatore di forme8Concetti avanzati di programmazione a oggetti
Composizione invece dell'ereditarietàTipi generici (classi e metodi)Delegati ed eventiAttributi e reflectionIDisposable e istruzione usingNozioni di base sull'iniezione delle dipendenze11Pattern di progettazione, parte 2
Pattern del ComandoPattern dell’AdattatorePattern del DecoratorePattern Template MethodPattern dello StatoPattern Composito3Architettura delle classi
Dati di istanza vs staticiParole chiave 'readonly' e 'const'Campi di supportoRiepilogo - Gestore di conti bancari6Incapsulamento
Modificatori di accessoProprietà per l'incapsulamentoImplementazione dell'occultamento dei datiModelli di immutabilitàRiepilogo - Registri degli studentiEsercitati da solo: Compilatore C# online