Eseguire una funzione richiamandola da una variabile

mercoledì 05 marzo 2008 - 13.16

denis.basei Profilo | Senior Member

Salve a tutti e buon pomeriggio...

Devo eseguire una funzione da vb net non richiamandola da codice attraverso il suo nome, come si fa normalmente, bensì leggendo il nome della stessa da un datatable. Cerco di essere più chiaro...

Eseguo una select sul datatable

Dim drAnaFunzioniEsterne As DataRow()
drAnaFunzioniEsterne = dsAppWorkdb.AnaFunzioniEsterne.Select("IDFunzioneProgramma = " & drAnaFunzioni(0)("IDFunzioneProgramma"))

La collezione datarow, in questo caso composta da una sola riga, mi ritorna nel campo drAnaFunzioniEsterne(0)("Funzione") il nome della funzione da eseguire. La funzione naturalmente esiste nel programma come public Function ... seguito dal nome as boolean

Come posso richiamare la funzione interpretando drAnaFunzioniEsterne(0)("Funzione") ?


Grazie
Denis B. - www.baseiengineering.com

aiedail92 Profilo | Expert

Ciao

per fare questo lavoro devi usare la reflection: per prima cosa ottieni il tipo contenente il metodo, quindi dal tipo ottieni il metodo attraverso il nome, e infine invochi il metodo passando gli opportuni argomenti:

Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra

Se la funzione non accetta parametri al posto di New Object() { ... } devi mettere Nothing

Questo procedimento ritorna un valore, che è Nothing se il metodo restituisce nothing o è una sub, oppure è un oggetto contenente il risultato della funzione.

Luca

denis.basei Profilo | Senior Member

Non sono molto pratico di reflection. Ho provato, probabilmente in modo improprio, quanto mi suggerisci ed il compilatore mi ritorna l'errore: object reference not set to an istance of an object.
Denis B. - www.baseiengineering.com

aiedail92 Profilo | Expert

Allora, le cause possono essere diverse...

Prova a scrivere la firma della funzione che richiami e la riga di codice dal quale viene richiamata, così posso focalizzare più in fretta il problema. Magari dacci anche il valore della variabile contenente il nome della funzione al momento della generazione dell'errore, magari è un problema di Maiuscole\Minuscole o qualcosa nella sintassi...

Luca

denis.basei Profilo | Senior Member

Questo è uno stralcio del codice

Dim drAnaFunzioniEsterne As DataRow()
drAnaFunzioniEsterne = dsAppWorkdb.AnaFunzioniEsterne.Select("IDFunzioneProgramma = " & drAnaFunzioni(0)("IDFunzioneProgramma"))
If drAnaFunzioniEsterne.Length = 1 Then
Try
Me.GetType().GetMethod(drAnaFunzioniEsterne(0)("Funzione")).Invoke(drAnaFunzioniEsterne(0)("Funzione"), Nothing)

Catch ex As Exception
MsgBox(ex.Message)
End Try
End If

Quando richiamo la riga me.getType.... drAnaFunzioniEsterne(0)("Funzione") vale 'Funzione1' che è il nome della function.
Denis B. - www.baseiengineering.com

aiedail92 Profilo | Expert

Dunque, l'errore è questo: il primo argomento della funzione Invoke deve essere la classe sulla quale richiamare il Metodo. Poichè la funzione che devi chiamare tu è nella classe nella quale stai lavorando, come primo parametro devi passare Me:

Me.GetType().GetMethod(drAnaFunzioniEsterne(0)("Funzione")).Invoke(Me, Nothing)

Quello che avevi scritto tu genera un'eccezione perchè drAnaFunzioniEsterne(0)("Funzione") non è una classe contenente il metodo drAnaFunzioniEsterne(0)("Funzione")

Quello che intendo dire è che fare

Me.GetType().GetMethod("Nome").Invoke(Me, Nothing)

equivale a scrivere

Me.Nome()

mentre

Me.GetType().GetMethod("Nome").Invoke("Nome", Nothing)

corrisponderebbe a chiamare il metodo "Nome" dalla classe String avente valore "Nome":

"Nome".Nome()

Spero di essere stato abbastanza chiaro

Luca

denis.basei Profilo | Senior Member

Ho seguito il tuo suggerimento ma l'errore è sempre lo stesso.
Denis B. - www.baseiengineering.com

aiedail92 Profilo | Expert

Allora, proviamo a dividere il lavoro per verificare quale è l'istruzione che genera l'errore. Modifica

Me.GetType().GetMethod(drAnaFunzioniEsterne(0)("Funzione")).Invoke(Me, Nothing)

in

Dim mytype As Type = Me.GetType() Dim funzione As System.Reflection.MethodInfo = _ mytype.GetMethod("Funzione1") funzione.Invoke(Me, Nothing)

Se l'errore si verifica alla prima istruzione (molto strano), significa che è stata generata un'eccezione quando tentavi di ottenere il tipo della tua classe. Se è la seconda istruzione a generare l'errore, significa che il tipo ottenuto corrisponde a Nothing (anche questo molto strano.) Se invece si verifica alla terza istruzione (la cosa più probabile) significa che è la funzione che non è stata trovata nella classe (quindi funzione è Nothing). Se il caso è questo significa che non c'è una corrispondenza fra il modello di ricerca predefinito e gli attributi della funzione (ad esempio non è dichiarata come pubblica) in tal caso ti consiglio di postare soltanto la dichiarazione della funzione, così da poterti dare i parametri di ricerca adatti.

Luca

denis.basei Profilo | Senior Member

Ciao Luca, intanto grazie per la cura nel descrivere i passi da seguire. Hai ragione, il problema nasce nell'istruzione di invoke. Ho definito la funzione come pubblica e poi ha funzionato. Ho risolto ma quel che è peggio è che non ho capito

Se l'istruzione funzione.invoke viene eseguita all'interno di una sub della classe che chiamo per comodità ClasseA e la funzione chiamata fa parte di ClasseA, perchè devo definire la funzione come pubblica?

Buona serata.
Denis B. - www.baseiengineering.com

aiedail92 Profilo | Expert

Prego

In realtà tu non sei obbligato a definire la funzione come pubblica. Anzi, potenzialmente, con la reflection, puoi accedere a tutti i membri, anche quelli privati. Il problema stava nel fatto che quando chiami il metodo GetMethod passando solo il nome del metodo, viene fatta la ricerca solo sui metodi pubblici. Quindi se vuoi specificare che il metodo può anche essere non pubblico devi passare una combinazione di BindingFlags.

Quindi puoi impostare nuovamente la funzione col modificatore di prima, e modificare così la chiamata a GetMethod:

Dim funzione As System.Reflection.MethodInfo = _ mytype.GetMethod("Funzione1", Reflection.BindingFlags.Public _ Or Reflection.BindingFlags.NonPublic _ Or Reflection.BindingFlags.Instance)

che esegue la ricerca fra i membri dell'istanza di mytype (quindi i metodi non shared), includendo metodi pubblici e non pubblici.

Luca

denis.basei Profilo | Senior Member

Grande Luca!

Sto appunto leggendo qualcosina sul manuale di vb 2005 in merito a reflection perchè mi ha aiutato ed è bene impararlo.



Grazie ancora e complimenti per la chiarezza di esposizione delle tue conoscenze.
Denis B. - www.baseiengineering.com

aiedail92 Profilo | Expert

É un piacere dare una mano!

Grazie a te delle lodi , alla prossima

Luca
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2024
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5