Domanda

Sento costantemente quanto sia pessimo usare la riflessione.Anche se generalmente evito la riflessione e raramente trovo situazioni in cui è impossibile risolvere il mio problema senza di essa, mi chiedevo...

Per coloro che hanno utilizzato la riflessione nelle applicazioni, avete misurato i risultati in termini di prestazioni ed è davvero così grave?

È stato utile?

Soluzione

È.Ma dipende da cosa stai cercando di fare.

Utilizzo la riflessione per caricare dinamicamente gli assembly (plugin) e la sua "penalità" in termini di prestazioni non è un problema, poiché l'operazione è qualcosa che faccio durante l'avvio dell'applicazione.

Tuttavia, se stai riflettendo all'interno di una serie di cicli nidificati con chiamate di riflessione su ciascuno, direi che dovresti rivisitare il tuo codice :)

Per le operazioni "un paio di volte", la riflessione è perfettamente accettabile e non noterai alcun ritardo o problema.È un meccanismo molto potente ed è utilizzato anche da .NET, quindi non vedo perché non dovresti provarlo.

Altri suggerimenti

Nel suo discorso Le prestazioni delle cose quotidiane, Jeff Richter mostra che chiamare un metodo mediante la riflessione significa 1000 volte più lento piuttosto che chiamarlo normalmente.

Il consiglio di Jeff:se devi chiamare il metodo più volte, usa la riflessione una volta per trovarlo, quindi assegnalo a a delegare, quindi chiamare il delegato.

Le prestazioni della riflessione dipenderanno dall'implementazione (le chiamate ripetitive dovrebbero essere memorizzate nella cache, ad esempio: entity.GetType().GetProperty("PropName")).Poiché la maggior parte della riflessione che vedo quotidianamente viene utilizzata per popolare entità da lettori di dati o altre strutture di tipo repository, ho deciso di confrontare le prestazioni in modo specifico sulla riflessione quando viene utilizzata per ottenere o impostare le proprietà di un oggetto.

Ho ideato un test che ritengo giusto poiché memorizza nella cache tutte le chiamate ripetute e calcola solo la chiamata effettiva SetValue o GetValue.Tutto il codice sorgente per il test delle prestazioni è in bitbucket all'indirizzo: https://bitbucket.org/grenade/accessortest.Il controllo è benvenuto e incoraggiato.

La conclusione a cui sono giunto è che non è pratico e non fornisce notevoli miglioramenti delle prestazioni per rimuovere la riflessione in un livello di accesso ai dati che restituisce meno di 100.000 righe in un momento in cui l'implementazione della riflessione è eseguita correttamente.

Graph of time (y) against number of entities populated(x)

Il grafico sopra mostra l'output del mio piccolo benchmark e mostra che i meccanismi che superano la riflessione, lo fanno notevolmente solo dopo aver superato i 100.000 cicli.La maggior parte dei DAL restituisce solo diverse centinaia o forse migliaia di righe alla volta e a questi livelli la riflessione funziona perfettamente.

Se non sei in un loop, non preoccuparti.

La mia esperienza più pertinente è stata la scrittura di codice per confrontare due entità di dati qualsiasi dello stesso tipo in un modello di oggetti di grandi dimensioni dal punto di vista delle proprietà.Ha funzionato, provato, ha corso come un cane, ovviamente.

Ero scoraggiato, poi dall'oggi al domani mi sono reso conto che senza cambiare la logica, avrei potuto utilizzare lo stesso algoritmo per generare automaticamente metodi per eseguire il confronto ma accedere staticamente alle proprietà.Non ci è voluto molto tempo per adattare il codice a questo scopo e ho avuto la possibilità di effettuare un confronto approfondito delle proprietà delle entità con codice statico che poteva essere aggiornato con un clic di un pulsante ogni volta che il modello a oggetti cambiava.

Il mio punto è:Nelle conversazioni con i colleghi ho più volte sottolineato che il loro uso della riflessione potrebbe essere quello di generare automaticamente codice da compilare piuttosto che eseguire operazioni di runtime e questo vale spesso la pena di essere preso in considerazione.

Non in modo massiccio.Non ho mai avuto problemi con lo sviluppo desktop a meno che, come afferma Martin, non lo utilizzi in un luogo stupido.Ho sentito che molte persone hanno paure assolutamente irrazionali riguardo alle sue prestazioni nello sviluppo desktop.

Nel Quadro compatto (in cui mi trovo di solito) però, è praticamente tutto anatema e dovrebbero essere evitati come la peste nella maggior parte dei casi.Posso ancora farla franca usandolo raramente, ma devo stare molto attento con la sua applicazione che è molto meno divertente.:(

È già abbastanza grave dover preoccuparsi anche della riflessione eseguita internamente dalle librerie .NET per il codice critico per le prestazioni.

L'esempio seguente è obsoleto, vero all'epoca (2008), ma corretto da tempo nelle versioni CLR più recenti.Tuttavia, la riflessione in generale è ancora una cosa un po’ costosa!

Caso in questione:Non utilizzare mai un membro dichiarato come "Oggetto" in un'istruzione lock (C#)/SyncLock (VB.NET) nel codice ad alte prestazioni.Perché?Perché CLR non può bloccarsi su un tipo di valore, il che significa che deve eseguire un controllo del tipo di riflessione in fase di esecuzione per verificare se l'oggetto è effettivamente un tipo di valore anziché un tipo di riferimento.

Come per tutte le cose nella programmazione, devi bilanciare il costo delle prestazioni con gli eventuali vantaggi ottenuti.La riflessione è uno strumento inestimabile se usato con cura.Ho creato una libreria di mapping O/R in C# che utilizzava la riflessione per eseguire i collegamenti.Ha funzionato straordinariamente bene.La maggior parte del codice di riflessione è stata eseguita una sola volta, quindi qualsiasi calo delle prestazioni è stato piuttosto ridotto, ma i vantaggi sono stati grandi.Se stessi scrivendo un nuovo algoritmo di ordinamento a fandangled, probabilmente non utilizzerei la riflessione, poiché probabilmente si ridimensionerebbe male.

Apprezzo di non aver risposto esattamente alla tua domanda qui.Il punto è che non ha molta importanza.Usa la riflessione dove appropriato.È solo un'altra funzionalità linguistica che devi imparare come e quando utilizzare.

La riflessione può avere un impatto notevole sulle prestazioni se la si utilizza per la creazione frequente di oggetti.Ho sviluppato un'applicazione basata su Blocco applicazione interfaccia utente composita che fa molto affidamento sulla riflessione.Si è verificato un notevole degrado delle prestazioni correlato alla creazione di oggetti tramite riflessione.

Tuttavia nella maggior parte dei casi non ci sono problemi con l'utilizzo della riflessione.Se la tua unica necessità è ispezionare qualche assemblaggio, lo consiglierei Mono.Cecil il che è molto leggero e veloce

La riflessione è costosa a causa dei numerosi controlli che il runtime deve effettuare ogni volta che si effettua una richiesta per un metodo che corrisponde a un elenco di parametri.Da qualche parte nel profondo, esiste un codice che esegue il loop su tutti i metodi per un tipo, ne verifica la visibilità, controlla il tipo restituito e controlla anche il tipo di ogni singolo parametro.Tutta questa roba costa tempo.

Quando esegui quel metodo internamente c'è del codice che fa cose come controllare di aver passato un elenco compatibile di parametri prima di eseguire il metodo di destinazione effettivo.

Se possibile, è sempre consigliabile memorizzare nella cache l'handle del metodo se si intende riutilizzarlo continuamente in futuro.Come tutti i buoni consigli di programmazione, spesso è opportuno evitare di ripetersi.In questo caso sarebbe uno spreco cercare continuamente il metodo con determinati parametri e quindi eseguirlo ogni volta.

Dai un'occhiata alla fonte e dai un'occhiata a cosa viene fatto.

Come per ogni cosa, si tratta di valutare la situazione.In DotNetNuke c'è un componente abbastanza fondamentale chiamato FillObject che utilizza la riflessione per popolare oggetti da righe di dati.

Questo è uno scenario abbastanza comune e c'è un articolo su MSDN, Utilizzo della riflessione per associare oggetti business ai controlli del modulo ASP.NET che copre i problemi di prestazioni.

Prestazioni a parte, una cosa che non mi piace dell'utilizzo della riflessione in quel particolare scenario è che tende a ridurre la capacità di comprendere il codice a colpo d'occhio, il che per me non sembra valere lo sforzo se si considera che si perde anche la compilazione sicurezza temporale rispetto a set di dati fortemente tipizzati o qualcosa del genere LINQ to SQL.

La riflessione non rallenta drasticamente le prestazioni della tua app.Potresti essere in grado di fare certe cose più velocemente non usando la riflessione, ma se Reflection è il modo più semplice per ottenere alcune funzionalità, allora usalo.Puoi sempre eseguire il refactoring del codice lontano da Reflection se diventa un problema di prestazioni.

Penso che scoprirai che la risposta è: dipende.Non è un grosso problema se vuoi inserirlo nell'applicazione dell'elenco delle attività.È un grosso problema se vuoi inserirlo nella libreria di persistenza di Facebook.

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