Domanda

Recentemente stavo parlando del C++ con un collega e mi sono lamentato del fatto che non c'era modo di prendere una stringa con il nome di un campo di classe ed estrarre il campo con quel nome;in altre parole, manca di riflessione.Mi guardò sconcertato e mi chiese quando mai qualcuno avrebbe avuto bisogno di fare una cosa del genere.

A priori non avevo una buona risposta da dargli, a parte "ehi, devo farlo adesso".Così mi sono seduto e ho stilato un elenco di alcune delle cose che ho effettivamente fatto con la riflessione in varie lingue.Sfortunatamente, la maggior parte dei miei esempi provengono dalla mia programmazione web in Python e speravo che le persone qui avessero più esempi.Ecco l'elenco che ho preparato:

  1. Dato un file di configurazione con righe come
    x = "Ciao mondo!"
    y = 5,0
    impostare dinamicamente i campi di alcuni config oggetto uguale ai valori in quel file.(Questo era ciò che avrei voluto fare in C++, ma in realtà non potevo farlo.)

  2. Quando si ordina un elenco di oggetti, ordinarlo in base a un attributo arbitrario dato il nome di tale attributo da un file di configurazione o da una richiesta web.

  3. Quando si scrive software che utilizza un protocollo di rete, la riflessione consente di chiamare metodi basati su valori di stringa da quel protocollo.Ad esempio, ho scritto un bot IRC che traducesse
    !some_command arg1 arg2
    in una chiamata al metodo actions.some_command(arg1, arg2) e stampa qualunque cosa quella funzione abbia restituito al canale IRC.

  4. Quando utilizzavo la funzione __getattr__ di Python (che è una specie di metodo_missing in Ruby/Smalltalk) stavo lavorando con una classe con un sacco di statistiche, come late_total.Per ogni statistica, volevo poter aggiungere _percent per ottenere quella statistica come percentuale del totale delle cose che stavo contando (ad esempio, stats.late_total_percent).La riflessione ha reso tutto questo molto semplice.

Quindi qualcuno qui può fornire qualche esempio tratto dalle proprie esperienze di programmazione di momenti in cui la riflessione è stata utile?La prossima volta che un collega mi chiede perché "vorrei fare qualcosa del genere" vorrei essere più preparato.

È stato utile?

Soluzione

Posso elencare i seguenti utilizzi per la riflessione:

  • Legatura tardiva
  • Sicurezza (codice introspettivo per motivi di sicurezza)
  • Analisi del codice
  • Digitazione dinamica (la digitazione duck non è possibile senza riflessione)
  • Metaprogrammazione

Alcuni usi della riflessione nel mondo reale dalla mia esperienza personale:

  • Sistema di plugin sviluppato basato sulla riflessione
  • Modello di programmazione orientato agli aspetti utilizzato
  • Analisi del codice statico eseguita
  • Utilizzati vari framework di Dependency Injection
  • ...

La riflessione è una buona cosa :)

Altri suggerimenti

Ho utilizzato la riflessione per ottenere informazioni sul metodo corrente per eccezioni, registrazione, ecc.

string src = MethodInfo.GetCurrentMethod().ToString();
string msg = "Big Mistake";
Exception newEx = new Exception(msg, ex);
newEx.Source = src;

invece di

string src = "MyMethod";
string msg = "Big MistakeA";
Exception newEx = new Exception(msg, ex);
newEx.Source = src;

È semplicemente più semplice copiare/incollare l'ereditarietà e generare codice.

Ora mi trovo in una situazione in cui ho un flusso di XML in arrivo via cavo e devo creare un'istanza di un oggetto Entità che si popolerà dagli elementi nel flusso.È più semplice usare la riflessione per capire quale oggetto Entità può gestire quale elemento XML piuttosto che scrivere un'istruzione condizionale gigantesca e da incubo di manutenzione.Esiste chiaramente una dipendenza tra lo schema XML e il modo in cui struttura e denomina i miei oggetti, ma controllo entrambi, quindi non è un grosso problema.

Ci sono molte volte in cui desideri creare un'istanza dinamica e lavorare con oggetti di cui il tipo non è noto fino al runtime.Ad esempio con OR-mapper o in un'architettura a plugin.I framework mocking lo usano se vuoi scrivere una libreria di logging e vuoi esaminare dinamicamente il tipo e le proprietà delle eccezioni.

Se ci penso un po’ più a lungo probabilmente riuscirò a trovare più esempi.

Trovo che la riflessione sia molto utile se i dati di input (come xml) hanno una struttura complessa che può essere facilmente mappata su istanze di oggetti o ho bisogno di una sorta di relazione "è un" tra le istanze.

Poiché la riflessione è relativamente semplice in Java, a volte la uso per dati semplici (mappe chiave-valore) in cui ho un piccolo set fisso di chiavi.Da un lato è semplice determinare se una chiave è valida (se la classe ha un setter setKey(String data)), dall'altro posso cambiare il tipo dei dati di input (testuali) e nascondere la trasformazione (ad esempio cast semplice to int in getKey()), in modo che il resto dell'applicazione possa fare affidamento su dati digitati correttamente.Se il tipo di alcune coppie chiave-valore cambia per un oggetto (ad es.form int to float), devo solo modificarlo nell'oggetto dati e nei suoi utenti, ma non devo tenere presente di controllare anche il parser.Questo potrebbe non essere un approccio sensato, se le prestazioni sono un problema...

Scrivere spedizionieri.Twisted utilizza le capacità riflessive di Python per inviare chiamate XML-RPC e SOAP.RMI utilizza l'API di riflessione di Java per l'invio.

Analisi della riga di comando.Creazione di un oggetto di configurazione in base ai parametri della riga di comando passati.

Quando si scrivono test unitari, può essere utile utilizzare la riflessione, anche se principalmente l'ho usato per ignorare i modificatori di accesso (Java).

Ho utilizzato la riflessione in C# quando nel framework era presente un metodo interno o privato o una libreria di terze parti a cui volevo accedere.

(Disclaimer:Non si tratta necessariamente di una procedura consigliata poiché i metodi privati ​​e interni potrebbero essere modificati nelle versioni successive.Ma ha funzionato per quello di cui avevo bisogno.)

Bene, nei linguaggi tipizzati staticamente, vorresti usare la riflessione ogni volta che hai bisogno di fare qualcosa di "dinamico".È utile per scopi di creazione di strumenti (scansione dei membri di un oggetto).In Java è utilizzato parecchio in JMX e nei proxy dinamici.E ci sono tantissimi casi una tantum in cui è davvero l'unica strada da percorrere (praticamente ogni volta che devi fare qualcosa che il compilatore non ti consente di fare).

Generalmente utilizzo la riflessione per il debug.La riflessione può visualizzare più facilmente e con maggiore precisione gli oggetti all'interno del sistema rispetto a un assortimento di istruzioni stampate.In molti linguaggi che hanno funzioni di prima classe, puoi anche invocare le funzioni dell'oggetto senza scrivere codice speciale.

C'è, tuttavia, un modo per fare quello che vuoi (ndr).Utilizza una tabella hash.Memorizzare i campi codificati rispetto al nome del campo.

Se lo desideri davvero, potresti creare funzioni Get/Set standard o creare macro che lo facciano al volo. #define GetX() Get("X") genere di cose.

Potresti persino implementare la tua riflessione imperfetta in questo modo.

Per l'utente avanzato, se è possibile compilare il codice, potrebbe essere possibile abilitare la generazione dell'output di debug e utilizzarlo per eseguire la riflessione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top