Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
7. Reflection
Abbiamo già incontrato in precedenza la classe System.Type che è la classe fondamentale per la re-
flection. Quando la reflection lo richiede, il CLR crea l’oggetto Type relativo a un tipo caricato.
Per ottenere informazioni sul tipo, è possibile utilizzare metodi, campi, proprietà e classi nidificate
dell’oggetto Type.
Queste ultime sono definite nel namespace System.Reflection (https://docs.microsoft.com/it-
it/dotnet/api/system.reflection).
La reflection può essere utilizzata anche per creare applicazioni definite visualizzatori di tipi, che con-
sentono agli utenti di selezionare i tipi e visualizzarne quindi le relative informazioni (come quello usa-
to dall’IDE di sviluppo Visual Studio).
Lezioni di Informatica (tutti i diritti riservati) – prof. Riccardo Crosato @ IIS “Marzotto-Luzzatti” 1
Programmazione Orientata agli Oggetti
la creazione di un oggetto di tipo Type può essere fatta in tre modi (facciamo riferimento alle classi di
esempio Persona, Studente e Docente le ultime due derivate dalla prima):
3. utilizzando il metodo statico Type.GetType() che riceve una stringa con il nome del tipo da
ispezionare:
t = Type.GetType("DemoReflection.Docente");
A questo punto possiamo utilizzare vari metodi della classe Type per ottenere le informazioni sul tipo.
Anzi, scriviamo un metodo che riceve un parametro di tipo Type e restituisce una stringa con varie in-
formazioni sul tipo:
private string OttieniInformazioniTipo(Type t)
{
string msg = "";
if (t == null)
msg += "\r\nTipo nullo";
else
{
ricaviamo nome, spazio di nomi e nome completo (dato da namespace.nome)
msg += "\r\nNome tipo: " + t.Name;
msg += "\r\nSpazio di nomi: " + t.Namespace;
msg += "\r\nNome completo: " + t.FullName;
ricaviamo il tipo dal quale deriva il tipo esaminato:
Type tipoBase = t.BaseType;
if (tipoBase != null)
msg += "\r\nTipo base: " + tipoBase.Name;
Lezioni di Informatica (tutti i diritti riservati) – prof. Riccardo Crosato @ IIS “Marzotto-Luzzatti” 2
Programmazione Orientata agli Oggetti
quindi, passiamo ad elencare tutti i membri pubblici del tipo (costruttori, campi, metodi e proprietà)
attraverso l’utilizzo del metodo GetMembers() che restituisce un array di oggetti di tipo MemberInfo
per mezzo dei quali possiamo ricavare informazioni sul membro come ad esempio tipo di membro
(Method, Property, Constructor, Field,...) e nome:
msg += "\r\nMEMBRI PUBBLICI: ";
MemberInfo[] membriPubblici = t.GetMembers();
foreach (MemberInfo m in membriPubblici)
msg += "\r\n" + m.MemberType + " " + m.Name;
anziché usare il metodo GetMembers() possiamo usare GetFields() per ottenere informazioni solo sui
campi:
msg += "\r\nCAMPI PUBBLICI: ";
FieldInfo[] campi = t.GetFields();
foreach (FieldInfo f in campi)
msg += "\r\n" + f.Name;
oppure sui costruttori sfruttando il metodo GetConstructors() che restituisce un array di oggetti di ti-
po ConstructorInfo. Per ogni costruttore è possibile utilizzare il metodo GetParameters() per ottenere
informazioni sui parametri del costruttore attraverso oggetti di classe ParameterInfo:
msg += "\r\nCOSTRUTTORI: ";
ConstructorInfo[] costruttori = t.GetConstructors();
foreach (ConstructorInfo c in costruttori)
{
// ricava i parametri dei costruttori
string s = "";
ParameterInfo[] parametri = c.GetParameters();
foreach (ParameterInfo pi in parametri)
s += pi.ToString() + " ";
Lezioni di Informatica (tutti i diritti riservati) – prof. Riccardo Crosato @ IIS “Marzotto-Luzzatti” 3
Programmazione Orientata agli Oggetti
cbxClassi.Items.Clear();
foreach (Type tipo in tipi)
// se il tipo è derivato direttamente (o indirettamente) da Persona
if (tipo.IsSubclassOf(t))
cbxClassi.Items.Add(tipo.FullName); // lo aggiunge al ComboBox
Lezioni di Informatica (tutti i diritti riservati) – prof. Riccardo Crosato @ IIS “Marzotto-Luzzatti” 4
Programmazione Orientata agli Oggetti
Sfruttiamo il metodo statico Type.GetType() per ottenere, nella variabile t, il riferimento al tipo scelto
in base alla stringa che ne contiene il nome (la scelta fatta nel ComboBox), quindi usiamo la classe Sy-
stem.Activator ed il suo metodo CreateInstance() per creare una istanza del tipo t:
Persona p;
if (t != null)
{
// Activator contiene metodi per creare tipi di oggetti
// è necessario il cast perchè Activator crea un oggetto di tipo Object
p = Activator.CreateInstance(t) as Persona;
if (p != null)
MessageBox.Show("Oggetto di tipo "+
p.GetType().Name + " creato a run-time con successo");
}
}
Nota: una implementazione alternativa poteva essere quella di sostituire l’istruzione all’interno del ci-
clo foreach del metodo btnPopolaComboBox_Click con cbxClassi.Items.Add(tipo) (aggiungen-
do cioè direttamente il riferimento all’oggetto Type).
Quindi nel metodo btnCreaOggetto_Click precedente sostituire la prima istruzione con
Lezioni di Informatica (tutti i diritti riservati) – prof. Riccardo Crosato @ IIS “Marzotto-Luzzatti” 5
Programmazione Orientata agli Oggetti
Con la chiamata che abbiamo usato nel codice precedente viene invocato il costruttore senza parame-
tri del tipo t, per cui se questo non esiste, l’istruzione solleva un’eccezione. Assumiamo di aver inserito
nelle classi Studente e Docente un costruttore senza parametri.
Un altro modo per creare oggetti del tipo t può sfruttare il metodo, della classe Type,
GetConstructor() che restituisce un oggetto di tipo CostructorInfo. Sull’oggetto restituito può essere
richiamato il metodo Invoke() che esegue il costruttore.
Il metodo GetConstructor() cerca un costruttore che abbia la firma specificata; la firma viene
specificata attraverso un array di tipo Type. Se viene passato un array vuoto (attenzione: non nullo ma
di zero elementi) verrà cercato il costruttore senza parametri.
In conclusione il codice precedente, che usava CreateInstance(), può essere sostituito dal seguente:
ConstructorInfo ctr;
a titolo di esempio, supposto che le classi abbiano un costruttore con due parametri di tipo stringa, per
invocarlo dovremo aver scritto un codice come il seguente:
// ottiene il riferimento al costruttore a due parametri stringa
ctr = t.GetConstructor(new Type[] { typeof(string), typeof(string) });
Infine, un’ulteriore strada, simile alla precedente, è quella di usare il metodo GetConstructors() che,
come abbiamo visto nel primo paragrafo, restituisce un array di tipo CostructorInfo con tutti i costrut-
tori della classe.
I costruttori sono elencati nell’array nell’ordine in cui sono stati definiti nella classe; se quindi, ad
esempio, il costruttore senza parametri è il primo, possiamo usare le seguenti istruzioni per richiamar-
lo:
ctr = t.GetConstructors()[0];
p = ctr.Invoke(null) as Persona;
Lezioni di Informatica (tutti i diritti riservati) – prof. Riccardo Crosato @ IIS “Marzotto-Luzzatti” 6
Programmazione Orientata agli Oggetti
Scriviamo un metodo che riceve un’espressione, definisce una classe statica contenente un metodo
apposito che esegue l’espressione, compila la classe e ricava, dal codice compilato, un riferimento al
metodo:
public static MethodInfo CompilaEspressione(string espressione)
{
// esempio di codice per sistemazione l'espressione secondo la sintassi C#
espressione = espressione.ToLower();
espressione = espressione.Replace("sen", "Math.Sin");
espressione = espressione.Replace("pi", "Math.PI");
Lezioni di Informatica (tutti i diritti riservati) – prof. Riccardo Crosato @ IIS “Marzotto-Luzzatti” 7
Programmazione Orientata agli Oggetti
Sfrutteremo il metodo precedente nella nostra applicazione, di cui è mostrata l’interfaccia grafica:
l’utente inserisce la funzione nel controllo cbxFunzione e clicca sul pulsante “Compila espressione”
per generare il metodo che verrà poi invocato ad ogni calcolo dell’espressione.
Lezioni di Informatica (tutti i diritti riservati) – prof. Riccardo Crosato @ IIS “Marzotto-Luzzatti” 8
Programmazione Orientata agli Oggetti
Dichiariamo un attributo globale di tipo MethodInfo che conterrà il riferimento al metodo compilato:
Se non vi sono stati errori di sintassi nell’espressione, il metodo è stato compilato e abbiamo un suo
riferimento nella variabile funzione.
A questo punto l’utente può calcolarne il valore cliccando sul pulsante “Calcola espressione” il quale
richiama un metodo CalcolaEspressione che fa uso del metodo Invoke. Il metodo Invoke esegue il
metodo e riceve un primo parametro che è l’oggetto sul quale eseguire il metodo (nel nostro caso è
null perchè il metodo è statico) ed un secondo parametro che è una lista di Object contenenti i para-
metri del metodo (nel nostro caso uno solo, il valore di x):
Lezioni di Informatica (tutti i diritti riservati) – prof. Riccardo Crosato @ IIS “Marzotto-Luzzatti” 9