La riflessione, in particolare sui membri privati, è sbagliata
- La riflessione rompe il tipo di sicurezza. Puoi provare a invocare un metodo che non esiste (più), o con parametri sbagliati, o con troppi parametri, o non abbastanza ... o anche nell'ordine sbagliato (questo è il mio preferito :)). A proposito, anche il tipo di ritorno potrebbe cambiare.
- La riflessione è lenta.
La riflessione dei membri privati infrange il principio di incapsulamento e quindi espone il codice a quanto segue:
- Aumenta la complessità del tuo codice perché deve gestire il comportamento interno delle classi. Ciò che è nascosto dovrebbe rimanere nascosto.
- Semplifica la rottura del codice poiché verrà compilato ma non verrà eseguito se il metodo ha cambiato nome.
- Rende il codice privato facile da violare perché se è privato non è destinato a essere chiamato in quel modo. Forse il metodo privato prevede uno stato interiore prima di essere chiamato.
E se dovessi farlo comunque?
Ci sono così casi, quando dipendi da una terza parte o hai bisogno di alcune API non esposte, devi fare qualche riflessione. Alcuni lo usano anche per testare alcune classi che possiedono ma che non vogliono cambiare l'interfaccia per dare accesso ai membri interni solo per i test.
Se lo fai, fallo bene
- Mitigare il facile da rompere:
Per mitigare il problema di una facile interruzione, la cosa migliore è individuare eventuali interruzioni testando unità test che verrebbero eseguite in una build di integrazione continua o simili. Ovviamente, significa che usi sempre lo stesso assembly (che contiene i membri privati). Se usi un carico dinamico e una riflessione, ti piace giocare con il fuoco, ma puoi sempre cogliere l'eccezione che la chiamata può produrre.
- Mitigare la lentezza della riflessione:
Nelle versioni recenti di .Net Framework, CreateDelegate ha battuto un fattore 50 invocato da MethodInfo:
// The following should be done once since this does some reflection
var method = this.GetType().GetMethod("Draw_" + itemType,
BindingFlags.NonPublic | BindingFlags.Instance);
// Here we create a Func that targets the instance of type which has the
// Draw_ItemType method
var draw = (Func<TInput, Output[]>)_method.CreateDelegate(
typeof(Func<TInput, TOutput[]>), this);
draw
le chiamate sono intorno a 50x più veloce di MethodInfo.Invoke
utilizzare draw
come standard Func
del genere:
var res = draw(methodParams);
Controlla questo mio post per vedere il benchmark su invocazioni di metodi diversi