Domanda

Che cosa è esattamente la riflessione? Ho letto l'articolo di Wikipedia su questo argomento e ho capito che si tratta di una sorta di meta-programmazione, in cui il programma può modificare se stessa in fase di esecuzione, ma che cosa significa? In che tipo di situazioni è questo un buon approccio e quando è il migliore per usarlo?

È stato utile?

Soluzione

La riflessione è una struttura dove è possibile interrogare un oggetto sui suoi attributi in fase di esecuzione. Ad esempio, Python, Java e .Net sono dotate di servizi dove si possono trovare le variabili di istanza o metodi di un oggetto.

Un esempio di applicazione di riflessione è uno strato di mappatura O / R. Alcuni usano riflessione per costruire un oggetto quering sue proprietà in fase di esecuzione e il popolamento dinamicamente un'istanza. Questo ti permette di fare questo programatically in base ai metadati da una sorta di dizionario di dati senza dover ricompilare l'applicazione.

Per fare un semplice esempio, io uso Python, perché le sue strutture di riflessione sono molto semplici da utilizzare e coinvolgere meno boilerplate di quelle di Java o .Net.

ActivePython 2.5.2.2 (ActiveState Software Inc.) based on
Python 2.5.2 (r252:60911, Mar 27 2008, 17:57:18) [MSC v.1310 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
>>> class foo:
...     def __init__(self):
...             self.x = 1
...
>>> xx = foo()      # Creates an object and runs the constructor
>>> xx.__dict__     # System metadata about the object
{'x': 1}
>>> a = xx.__dict__ # Now we manipulate the object through 
>>> a['y'] = 2      # its metadata ...
>>> print xx.y      # ... and suddenly it has a new instance variable
2                   
>>>

Ora, abbiamo usato riflessione di base per esaminare le variabili di un oggetto arbitrario istanza. La variabile speciale __dict__ su Python è una proprietà di sistema di un oggetto che ha una tabella hash dei suoi membri calettati dal nome della variabile (o metodo). Abbiamo riflessivo esaminato l'oggetto e utilizzato le strutture di riflessione per colpire artificialmente una seconda variabile di istanza in esso, che possiamo quindi visualizzare invocando come una variabile di istanza.

Si noti che questo particolare trucco non funziona su Java o .Net, come le variabili di istanza sono fissi. Il sistema tipo di queste lingue non consente nuove variabili di istanza da aggiungere in fase di esecuzione nel modo in cui il sistema di digitazione di pitone 'anatra' fa. Tuttavia, si potrebbe avere riflessivo aggiornato il valore di una variabile di istanza che è stata dichiarata nella definizione del tipo.

È inoltre possibile utilizzare la riflessione per costruire dinamicamente chiamate di metodi e di eseguire vari altri trucchetti, come istanza di un oggetto in base a un parametro. Ad esempio, se si ha una sorta di sistema basato plug-in cui alcune capacità erano opzionali, è possibile utilizzare la riflessione per interrogare il plugin su quali servizi ha offerto (forse interrogando se alcune interfacce sono state implementate) senza la necessità di metadati esplicito.

Molte interfacce linguaggio dinamico come ad esempio OLE utilizzo di automazione di riflessione come parte integrante dell'interfaccia.

Altri suggerimenti

Non è tanto Modifica il codice in fase di esecuzione, ma l'esame di oggetti e chiedendo loro di eseguire codice senza conoscere il loro tipo statico.

Un modo semplice per descrivere che sarebbe "un modo un po 'doloroso di fare un linguaggio a tipizzazione statica si comportano in modo dinamico".

EDIT: Usi:

  • Configurazione (ad esempio prendere un file XML che specifica i tipi e le proprietà, quindi costruire oggetti appropriati)
  • (Test di unità che sono identificati per nome o attributi)
  • test
  • servizi Web (nel .NET, almeno, un sacco di riflessione viene utilizzato nel motore di servizio Web core)
  • cablaggio evento automatico - fornire un metodo con un nome appropriato, ad esempio SubmitButton_Click e ASP.NET attribuirà che metodo come un gestore per l'evento SubmitButton s 'il Click (se avete autowiring acceso)

E 'una buona idea? Ebbene, solo quando le alternative sono dolorose. Io preferisco tipizzazione statica quando non ottiene nel senso - allora si ottiene un sacco di tempo di compilazione bontà, ed è più veloce anche. Ma quando si fa bisogno, riflessione permette di fare varie cose che altrimenti semplicemente non sarebbe possibile.

Il primo buon esempio mi viene in mente la parte superiore della mia testa è per quando si ha bisogno per eseguire un insieme di metodi su un dato oggetto senza sapere a tempo di compilazione quanto esisteranno metodi in esso.

framework di unit test Prendiamo ad esempio. La classe di test runner che è responsabile per l'esecuzione di tutti i test di unità non sapere in anticipo ciò che si sta per denominare i metodi. Tutto ciò che sa è che essi saranno preceduti da "test" (o, nel caso di Java 5, annotato con @Test). Così, quando data una classe di test, si riflette su quella classe al fine di ottenere un elenco di tutti i metodi in esso. Poi, si itera attraverso quei nomi di metodo come stringhe e chiama i metodi sull'oggetto se iniziano con "test". Che non sarebbe possibile senza riflessione. E questo è solo un esempio.

Riflessione è stato utile per me in almeno 1 progetto mi viene in mente. Abbiamo scritto un programma interno "Process Manager" che esegue un sacco di processi aziendali chiave a determinati intervalli. Il progetto è impostato in modo che il nucleo è in realtà solo un servizio di Windows con oggetti di timer che sparano fuori ogni 30 secondi o giù di lì e verificare la presenza del lavoro da fare.

Il lavoro effettivo è stato fatto in una libreria di classi (appropriatamente chiamato "WorkerLib"). Definiamo classi con metodi pubblici che eseguono determinati compiti (spostamento di file in giro, caricamento dei dati in siti remoti, ecc) L'idea è che il servizio principale può chiamare i metodi della libreria operaio senza sapere nulla circa i metodi che sta chiamando. Questo ci permette di creare una pianificazione nel database per i lavori, e anche aggiungere nuovi metodi nella libreria di classi, senza mai dover modificare il sistema centrale.

L'idea di base è che siamo in grado di utilizzare la riflessione nel servizio di base per eseguire i metodi i cui nomi abbiamo memorizzato nel database di definizione dei programmi. E 'abbastanza carino in pratica. Il nostro servizio di base è solida e maniglie di esecuzione dei lavori, se necessario, mentre la biblioteca lavoratore reale può essere ampliata e modificata, se necessario, senza il nucleo curarsi.

Se avete bisogno di ulteriori spiegazioni, non esitate a chiedere. Questo era semplicemente il modo migliore che potevo pensare di spiegare uno scenario del mondo reale in cui la riflessione realmente rende le cose più facili per noi.

Un altro esempio: Ho codice che uso che prende l'uscita di un database - che è un insieme di righe con le colonne di nome - e la immette in un array di oggetti. I scorrere le righe, e se l'oggetto bersaglio ha una proprietà con lo stesso nome e tipo, ho impostato. In questo modo per il mio codice di dati-ottenere solo cercando qualcosa di simile:

SqlDataReader sdr = Helper.GetReader("GetClientByID", ClientID);
Client c = new Client();
FillObject(sdr, c);
return c;

In realtà, la riflessione deve essere pensato come una sorta di un amplificatore per il codice. Si può fare buon codice migliore e più pulita, e codice cattivo peggio. Che cosa fa? Esso consente davvero di scrivere codice, che il tuo non del tutto certo che cosa sta andando a fare in quel momento si scrive. Avete un'idea generale, ma ti permette di non codificare quali oggetti, i metodi e le proprietà sta andando eseguire quando il programma viene compilato.

Altri messaggi sono corrette quando dicono che permette al programma di eseguire codice sulla base di valori di configurazione, ma è il potere reale è che permette di piegare gravemente le regole della programmazione orientata agli oggetti. Questo è davvero quello che fa. È un po 'come girare le misure di sicurezza fuori. metodi e proprietà private potranno essere visitate attraverso la riflessione insieme a quasi tutto il resto.

Un esempio eccellente quando MS utilizza la riflessione è con rilegatura dati oggetto dati. Si specifica il nome del campo di testo e campo di dati per un oggetto di legarsi a un elenco a ecc verso il basso, e il codice rispecchia l'oggetto e tira fuori le informazioni appropriate. L'oggetto associazione dati fa lo stesso processo più e più volte, ma non sa che tipo di oggetto che deve legarsi con. La riflessione è un modo conveniente di scrivere un po 'di codice per gestire tutti i casi possibili.

In Java è fondamentalmente un modo per creare un'istanza di una classe senza sapere su di esso prima mano. Dire che si desidera che l'utente sia in grado di modificare un file di configurazione con l'aggiunta della classe che vogliono il vostro programma da utilizzare (dire di avere numerose implementazioni di qualche interfaccia). Con la riflessione è possibile creare un oggetto in base a solo il suo nome, firma del metodo, ecc. . e poi lanciarla alla vostra interfaccia.

riflessione è utile per la configurazione runtime, consentendo parti di un sistema per essere guidato attraverso configurazione esterna.

Per esempio, una fabbrica di classe potrebbe costruire diversi tipi concreti sulla base di un file di input, in cui i tipi concreti richiedono informazioni di configurazione diversa per chiamare un costruttore di cemento piuttosto che utilizzare un Interface Builder. (Il metodo costruttore dell'oggetto essendo posizionata utilizzando la riflessione).

La riflessione è (praticamente) la capacità di un programma per eseguire query per le informazioni tipo che era disponibile per il compilatore. Così, per esempio, dato il nome di un tipo è possibile interrogare per i metodi in esso contenuti. Poi, per ogni metodo è possibile interrogare per i tipi di parametri che prendono ecc ecc ecc.

E 'utile per la configurazione di runtime in cui hai un file di configurazione che specifica il comportamento dell'applicazione. La configurazione può contenere i nomi dei tipi concreti che si dovrebbe usare (come spesso accade con i contenitori CIO). Usando riflessione è possibile creare un'istanza di questo tipo concreto (tramite un API di riflessione) e usarlo.

Ti do un esempio.

Come un esercizio di programmazione ho scritto un correttore di file mp3. Si analizza la mia libreria musicale e visualizza i tag ID1 / ID2 che mi interessano in un DataGridView. Io uso riflessione per ottenere le proprietà della classe informazioni mp3 senza il codice di interfaccia utente di dover sapere nulla di quella classe. Se voglio cambiare ciò che informazioni viene visualizzata posso né modificare la classe informazioni mp3 o modificare la propria configurazione (a seconda di come ho scritto la classe) e non c'è bisogno di aggiornare l'interfaccia utente.

E 'significava anche che sono stato in grado di utilizzare Dependency Injection per utilizzare lo stesso da un capo all'altro visualizzare le informazioni relative fotografie digitali semplicemente scambiando la classe libreria di dati.

Assiemi contengono moduli, moduli contengono tipi e tipi contengono membri. Riflessione fornisce oggetti che incapsulano assemblati, moduli e tipi. È possibile utilizzare la reflection per creare dinamicamente un'istanza di un tipo, associare il tipo da un oggetto esistente, o di ottenere il tipo da un oggetto esistente. È quindi possibile richiamare i metodi del tipo o accedere i suoi campi e proprietà. Gli usi tipici di riflessione sono i seguenti:

  • Usa Assemblaggio per definire e assiemi di carico, moduli di carico elencati nel manifesto assemblaggio e individuare un tipo da questo assemblaggio e creare un'istanza di esso.
  • Utilizza il modulo per scoprire informazioni quali l'assembly che contiene il modulo e le classi nel modulo. È inoltre possibile ottenere tutti i metodi globali o altri metodi non globali specifici definiti sul modulo.
  • Usa ConstructorInfo per trovare informazioni come il nome, i parametri, modificatori di accesso (ad esempio, pubblica o privata) e dettagli di implementazione (come astratto o virtuale) di un costruttore. Utilizzare i GetConstructors o metodo GetConstructor di un tipo di invocare un costruttore specifica.
  • Usa MethodInfo per trovare informazioni come il nome, tipo di ritorno, i parametri, modificatori di accesso (ad esempio, pubblica o privata) e dettagli di implementazione (come astratto o virtuale) di un metodo. Utilizzare i GetMethods o metodo GetMethod di un tipo per richiamare un metodo specifico.
  • Usa FieldInfo per trovare informazioni come il nome, modificatori di accesso (ad esempio, pubblici o privati) dettagli e implementazione (come statica) di un campo, e per ottenere o valori campo insieme.
  • Usa EventInfo per scoprire informazioni come il nome, il tipo di dati gestore di eventi, gli attributi personalizzati, tipo dichiarando, e il tipo di un evento riflessa, e per aggiungere o rimuovere i gestori di eventi.
  • Usa PropertyInfo per scoprire informazioni come il nome, il tipo di dati, il tipo di dichiarazione, il tipo di riflesso, e sola lettura o scrivibile lo stato di una proprietà, e per ottenere o impostare i valori delle proprietà.
  • Usa ParameterInfo per trovare informazioni come il nome, il tipo di dati di un parametro, se un parametro è un parametro di ingresso o di uscita, e la posizione del parametro in una firma del metodo.
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top