2009-07-30 14 views
33

Vedo molte domande in C#, .net risolte qui utilizzando la riflessione. Per me, molti sembrano piegare le regole al costo di un buon design (OOP). Molte delle soluzioni sembrano non curabili e "scripty".Sta usando la riflessione un odore di design?

L'uso della riflessione è una buona pratica in generale? Ci sono cose che possono essere risolte solo con la riflessione?

edit:

Si prega di fornire esempi in cui la riflessione è l'unica buona soluzione.

+2

Vedo molte opinioni ma nessuna discussione sulle migliori pratiche. –

+1

Ci piace solo vedere il nostro nome in stampa. Vedere? -> –

+0

Alcuni di voi hanno sottolineato che la riflessione ha un posto nei quadri, nei test, nelle derisioni, ecc. Che ne dite delle applicazioni line-of-business? – Mank

risposta

0

No sua un pesante uso di riflessione da parte del framework dot net stessa che ha guadagnato popolarità tanto

uso F # usa pesantemente riflessione

+1

Possiamo dire che un framework ha requisiti di progettazione diversi rispetto alle applicazioni che lo usano? – Mank

+0

No. MS fornisce continuamente più funzionalità in base alla riflessione con ciascun framework. ad es. 4.0 introducono tipi dinamici. che di nuovo si basa sulla riflessione –

13

riflessione a volte è l'unico modo per fare certe cose. È uno strumento molto potente che può a volte essere abusato da qualcuno che conosce molto bene la riflessione, ma forse non qualcos'altro. Un uso eccessivo della riflessione quando qualcos'altro funzionerà meglio potrebbe essere un odore di progettazione ... ma più spesso probabilmente solo una cattiva programmazione.

7

Non direi che l'uso del riflesso è un odore di progettazione. È una caratteristica utile del framework che rende i linguaggi statici un po 'più dinamici. Ora dal punto di vista pratico cerco di evitare la riflessione se riesco a risolvere il mio problema senza di esso.

+0

concordato. Sto cercando altre risposte per vedere qualsiasi tipo di consenso. – Mank

2

Ci sono alcuni problemi che possono essere risolti solo con la riflessione, ma penso che possa e forse dovrebbe essere evitato ovunque sia possibile. C# è un linguaggio statico e sicuro per il tipo, quindi utilizza questo vantaggio. Usare la riflessione è spesso abbastanza incline all'errore, penso.

+0

Concordo sul fatto che la riflessione può essere abbastanza soggetta a errori a causa della sua natura dinamica. – Mank

2

come tutte le cose la risposta è "dipende"

Un uso valida di riflessione è in contesti, ad esempio, un quadro plug-in potrebbe fare uso di attributi per dichiarare le classi del plugin, test e beffardo quadri sono un altro esempio.

Ma sono d'accordo che in generale in una linea di business app, la maggior parte del tempo che sarebbe stato un "codice odore" (non sempre però ....)

+0

concordo. Ho scritto nel post di Umair che i framework hanno obiettivi di design diversi rispetto alle applicazioni line-of-business. I quadri di prova e di derisione sono esempi di buon uso della riflessione. – Mank

3

Da un grande potere arrivano grandi responsabilità, la riflessione è uno strumento molto potente e se usato correttamente molto bene, se usato in modo improprio è pessimo, il trucco è sapere quando il tuo utilizzo lo utilizza

+1

Vai spidoso! Partire! Per System.Reflection! –

0

Bene, le API di riflessione chiare ci sono perché soddisfano un bisogno e ci sono alcuni problemi che possono essere risolti solo con l'uso della riflessione. Fondamentalmente, la riflessione è necessaria quando è necessario prendere decisioni nel codice in base alle informazioni sul tipo disponibili solo in fase di esecuzione ma non in fase di compilazione.

+0

Esistono modelli di progettazione come il visitatore, strategia che consente di prendere decisioni in fase di progettazione in base alle informazioni sul tipo. – Mank

+0

Intendevo dire runtime invece del tempo di progettazione. – Mank

+1

Dire che sono "lì perché soddisfano un bisogno" è un argomento molto circolare, e potrebbe essere applicato altrettanto facilmente a praticamente qualsiasi funzione di qualsiasi API o linguaggio di programmazione. Molte funzionalità esistono semplicemente perché sembravano una buona idea in quel momento. Molti erano esperimenti. Molti sono stati aggiunti semplicemente per riempire una casella di controllo su un elenco di funzionalità. –

3

Come con qualsiasi altra tecnologia, se ci si concentra troppo su di esso si può iniziare ad applicarlo al tipo sbagliato di problemi.

Ci sono tuttavia cose che semplicemente non sono possibili senza riflessione; qualsiasi tipo di serializzazione generale è un ottimo esempio. Un altro sarebbe un qualsiasi tipo di framework plug-in che al momento della compilazione non abbia accesso a tutte le classi di cui potrebbe aver bisogno per lavorare in fase di esecuzione.

+1

La serializzazione è un buon esempio. È una preoccupazione trasversale nella maggior parte delle applicazioni. – Mank

0

A volte migliora effettivamente la riusabilità del codice. Come esempio particolare, una volta ho scritto un programma per importare un CSV in un database.Usando un ORM per creare classi per le tabelle, riflettendo su queste, sono stato in grado di creare un importatore in cui si dovevano rilevare solo situazioni eccezionali e l'aggiunta di una colonna potrebbe non aver richiesto altro che aggiungerla alla tabella db, e sapendo che esiste nel file.

Ma come altri hanno affermato, è principalmente un problema di uso corretto.

6

A mio modesto parere, la riflessione dovrebbe essere l'ultima risorsa. La riflessione rende il codice davvero difficile da capire semplicemente guardandolo poiché la semantica della lingua può essere alterata in modi molto strani.

Lo considererei un odore. Forse non è una cattiva pratica, ma qualcosa che alza un sopracciglio.

44

Esempi:

  • caricamento dinamico di tipi tramite configurazione
  • Uso "convenzione" registrazione stile (registro componenti con contenitore che implementano un'interfaccia o avere un certo convenzione di denominazione)
  • Controllo di/utilizzando attributi personalizzati/tipo metadati

Riflesso è uno strumento, come "lancia". dovresti usare buttare ovunque? No! Quindi è un odore di codice usare il lancio?

+5

Esattamente quello che avrei scritto. – Alex

+0

Esattamente quello che avrei voluto scrivere – Benoittr

0

Tutte le fasi di riflessione consentono di osservare i tipi in fase di esecuzione. Se sei un hacker, suppongo che potresti potenzialmente codificare un aggeggio di Rube Goldberg con esso, ma lo stesso si può dire di molte altre tecniche.

Molte funzioni di base del framework, come gli attributi, non funzionerebbero affatto senza una riflessione.

6

Concettualmente, la riflessione è un potente strumento da utilizzare come un gateway da non-codice in codice così come uno strumento polimorfico.

Ad esempio ...

  • prendendo una rappresentazione di stringa di tipo e trasformandolo in un oggetto.
  • non framework hardcoding o plugin insieme.
  • utilizzando dinamicamente gli oggetti da diversi assiemi senza conoscere cosa sono in anticipo.
  • serializzare i dati senza scrivere il codice dedicato per farlo.

Utilizzato correttamente è uno strumento ingegnoso per portare il codice al livello successivo di riusabilità e flessibilità. Niente di male in questo.

L'unica volta che si tratta di un odore di progettazione è quando viene utilizzato per fare qualcosa che copre già la funzionalità convenzionale. (Ad esempio, non si desidera utilizzare Reflection per ottenere i valori di un DataRow o qualcosa del genere).

14

Per me, molti di loro sembrano flessione le regole a costo di un buon design (OOP). Molte delle soluzioni sembrano non gestibili e "scripty".

Onestamente, "buon design" ha poco a che fare con OOP. Direi che un odore di design molto più grande di cui preoccuparsi è la convinzione che un buon design sia esattamente uguale a OOP. Che non possiamo avere un buon design senza OOP e che non possiamo seguire le regole di OOP senza che questo diventi un buon design. È quasi tanto grave quanto l'ossessione della gente per gli "odori". I programmatori dovrebbero usare il loro cervello, non il loro naso.

L'uso del riflesso è una buona pratica in generale? Ci sono cose che possono risolvere solo per riflessione?

Per come la vedo io, la riflessione è principalmente un sintomo delle carenze linguistiche. Idealmente, un linguaggio dovrebbe consentire di fare ciò che vuoi senza "piegare le regole" attraverso la riflessione. Ma la maggior parte non lo fa, e C# non lo fa, quindi la riflessione è occasionalmente l'unica scelta sensata.

Ci sono un sacco di usi "corrette" di riflessione. Il caricamento dinamico di tipi/librerie sarebbe ovvio. O ispezionare attributi. La maggior parte dei framework di testing delle unità dipende anche dalla riflessione, il che va bene, perché devono essere un po 'invadenti per essere facili da usare e ottenere l'accesso al codice che vogliamo testare.

Ma la maggior parte del codice utente che esegue una sorta di ispezione del tipo, test in fase di esecuzione se un tipo implementa una determinata interfaccia o ha una determinata funzione membro, è un segno di qualcosa che, in un linguaggio ideale, non dovrebbe essere necessario .

Se si vuole considerare un odore, chiamare un linguaggio di odore, non è un disegno unico. (Ovviamente può essere usato troppo nel design, ma dove lo trovo più spesso, è una necessità a causa della mancanza di espressività della lingua)

+0

Ho convenuto che l'OOP non è l'unico buon progetto, ma è uno di quelli per molti problemi. Nella mia domanda intendevo usare la riflessione nei progetti OOP, ma penso di non essere stato chiaro. – Mank

+0

Buon punto sul buon design. – AraK

+3

@Mank: OOP non è uno dei buoni progetti, il ruolo di OOP è quello di guidare gli sviluppatori per evitare il peggior progetto. Sono totalmente d'accordo con tutti i punti jalf. C# ha un "odore del linguaggio" e la riflessione è una soluzione rapida del linguaggio C# e difetti di progettazione OOP. Uno dei difetti di progettazione OOP è il modello di ereditarietà superficiale. – alpav

12

Una volta un programma che elaborava i file (quanto è generica quella descrizione)

Utilizzando la riflessione tutto quello che dovevi fare era inserire una DLL in una cartella, l'app lo avrebbe prelevato e usato il reflection per cercare classi che implementassero una determinata interfaccia e controllare alcuni attributi. Non c'era bisogno di file di configurazione. Basta andare e venire, il che era comodo per un sistema di produzione dato che non richiedevamo tempi di fermo.

Come con la maggior parte delle soluzioni. ci sono molti altri modi per raggiungere lo stesso scopo, ma la riflessione lo ha reso abbastanza facile.

+1

Grazie per l'esempio. Come altri hanno già detto, i plugin sono un buon uso della riflessione. – Mank

+1

Questo è esattamente come lo faccio anch'io. Odio dover registrare ogni tipo di plugin in qualche file di configurazione o registro o qualsiasi altra cosa (il che mi ha dato un po 'di mal di testa qualche volta prima di iniziare a utilizzare .NET). – Botz3000

1

No, la riflessione non è un odore di progettazione. Potrebbe, probabilmente, essere chiamato "odore di lingua/piattaforma".

Reflection è utilizzato perché i metadati di codice e codice vengono entrambi memorizzati nell'assembly. Pertanto, vengono sempre aggiornati e sincronizzati. È possibile codificare le convenzioni generali sui metadati anziché essere espliciti nel caso comune.

Per modularità in .NET, è un grande vantaggio che i moduli sono auto-descrittivi.

Questo potrebbe essere dovuto al mio sviluppo personale come programmatore, ma trovo che la riflessione sull'apprendimento promuova un'attenzione tanto necessaria per i risultati finali (assemblee). Insieme a TDD, ovviamente.

2

Reflection consente di esaminare in fase di esecuzione le stesse informazioni utilizzate dal compilatore in fase di compilazione. Di conseguenza, tutto ciò che si può fare con la riflessione può essere fatto senza riflessione durante la compilazione. Questo non significa che la riflessione non ha senso: potresti non sapere quale domanda esatta vuoi chiedere fino al runtime.

Se si conosce qualcosa al momento della compilazione, esprimerlo nel sistema di tipi. Questo ti permetterà di cogliere errori al momento della compilazione. Ad esempio,

string propVal = myObj.SomeProperty; 

Qui stiamo dicendo che sappiamo per certo che al momento della compilazione myObj ha una proprietà chiamata SomeProperty che è di un tipo che è assegnabile a string - e di fatto, anche se non è visibile qui, dobbiamo anche specificare un tipo di interfaccia o classe di myObj.

string propVal = (string)myObj.GetType() 
         .GetProperty("SomeProperty") 
         .GetValue(myObj, null); 

Qui stiamo dicendo che myObj potrebbe avere quella stessa proprietà - o potrebbe non (nel qual caso ci arriveremo un'eccezione in fase di esecuzione).

Il secondo, con la riflessione, sembra brutto, ma in C# 4.0 sembrerà praticamente identico. Spesso è anche più lento, ma dipende dal contesto e probabilmente sarà meno vero per le caratteristiche dinamiche in C# 4.0.

La vera distinzione rimane, tuttavia: la versione tipizzata staticamente ci aiuta a trovare errori durante la compilazione, invece di ritardare questa scoperta fino al runtime.

Quindi, se si vuole sfruttare appieno il sistema di tipo statico per catturare i bug durante la compilazione, provare a indicare le proprie ipotesi tramite il sistema di tipi, che equivale a dire: evitare la riflessione tranne dove realmente necessario.

1

Un buon uso della riflessione è quando si desidera implementare un'architettura aggiuntiva. Hai bisogno di un modo per specificare "ecco una DLL, vai a caricarla e prova a istanziare un tipo". Non conosci il tipo prima della mano; tutto quello che sai è che c'è una qualche interfaccia in cui puoi accedere. L'unico modo per farlo è con la riflessione.

La nostra applicazione ha un numero elevato di moduli che è possibile eseguire al suo interno. Piuttosto che codificare a fondo un elenco di classi che dobbiamo avviare quando selezioni un modulo, abbiamo una tabella di dati che elenca il nome della DLL del modulo e una classe da eseguire da esso. In questo modo, quando abbiamo bisogno di aggiungere un nuovo modulo, abbiamo solo bisogno di una nuova voce nella tabella. Il codice che avvia i moduli non cambia.

+0

+1 Questo è esattamente ciò che stiamo usando per Reflection. Non è un * odore di design * tanto quanto una necessità di fornire una ricca architettura di plugin/addin. Senza la riflessione, questo potrebbe essere un compito molto difficile da realizzare. – IAbstract

2

La programmazione è incentrata sulla costruzione di astrazioni. La riflessione è uno strumento molto potente per costruire astrazioni. Quindi no, se porta a meno codice che è più facile da capire, non direi che è un odore di design.

Alcuni di voi hanno sottolineato che la riflessione ha un posto nei quadri, nei test, nelle derisioni ecc. Che ne dite di applicazioni line-of-business?

Nella mia esperienza, quando si scrive un'applicazione line-of-business di alcune dimensioni, si finisce inevitabilmente per scrivere il proprio framework e le proprie librerie specifiche del dominio. È lì che la riflessione ha il suo posto.

0

Questo è uno degli odori più stordenti. Un linguaggio "completamente chiuso" non ha bisogno di riflessione.

+1

Puoi chiarire cosa intendi con "completamente chiuso"? – UserControl

0

Chiunque può vedere i benefici dell'utilizzo della riflessione e penso che la riflessione possa aiutarvi a ottenere un design migliore e soprattutto i concetti di progettazione OOP senza scrivere molto più codice.

Ad esempio, è possibile creare strati liberamente accoppiati che dipendono dall'astrazione e utilizzare la riflessione per controllare il comportamento specifico delle istanze in fase di esecuzione.

Ovviamente: strati/componenti UI generalizzati.

La flessibilità e la produttività di ASP.Net MVC e dati dinamici sono solo un esempio, inoltre è possibile vedere anche GridView.

1

Sono nel bel mezzo di un progetto che utilizza (per la mia prima volta, sempre) Riflessione. Devo ammettere, non sembra molto buono. Normalmente mi sforzo di commentare molto minimamente, nella convinzione che il codice dovrebbe essere auto-commentante nella misura massima possibile, ma con questo progetto aggiungo commenti frequenti; questo è sia per spiegare cosa sta succedendo al prossimo sviluppatore che potrebbe dover mantenere il codice, sia come "pensare ad alta voce" a mio vantaggio.

In conclusione: se non sembra ovvio, aggiungere commenti. Pensa sempre alla persona che viene dopo di te che potrebbe avere a che fare con il tuo casino. La riflessione può apparire disordinata, quindi commentare di conseguenza.

Problemi correlati