2015-02-03 6 views
9

Nella mia applicazione VB.NET, l'evento AppDomain.CurrentDomain.AssemblyResolve si è iscritto a un gestore. Il ResolveEventHandler che è stato sottoscritto a questo evento è stato aggiunto a monte del mio codice (per quello che ne so, System.AppDomain ha il suo Private Method iscritto all'evento) ... è possibile rimuovere tutti i gestori da questo evento, in modo che possa aggiungere il mio proprio gestore e assicurarsi che sia il solo uno?E 'possibile rimuovere un EventHandler VB.NET che la tua classe non ha aggiunto?

sostanza che sto cercando di fare questo:

RemoveHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf ClassX.MethodX 

Ma io non so che cosa ClassX o MethodX sono in questo esempio perché non ho ancora aggiunto un gestore a questo evento, e questo gestore è stato aggiunto dal codice upstream. Sto usando il metodo descritto qui per controllare evento se ogni gestore viene sottoscritto: https://stackoverflow.com/a/2953318/734914

Edit: sono stato in grado di capire quale metodo viene sottoscritto l'evento, utilizzando la finestra immediata durante il debug.

? DirectCast(gettype(System.AppDomain).GetField("AssemblyResolve", BindingFlags.Instance or BindingFlags.NonPublic).GetValue(AppDomain.CurrentDomain) , ResolveEventHandler) 
{System.ResolveEventHandler} 
    _methodBase: Nothing 
    _methodPtr: 157334028 
    _methodPtrAux: 1827519884 
    _target: {System.ResolveEventHandler} 
    **Method: {System.Reflection.Assembly ResolveAssembly**(System.Object, System.ResolveEventArgs)} 
    Target: Nothing 

ora sto cercando di rimuoverlo, in questo modo, perché non è un metodo pubblico:

RemoveHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf GetType(Reflection.Assembly).GetMethod("ResolveAssembly") 

ma che dà un errore di compilazione dicendo: "il parametro AddressOf deve essere il nome di una metodo". Quindi io non sono sicuro di come specificare un metodo non pubblico qui

+0

No, non è possibile farlo. –

+0

è questa app winforms o una lib di classe? – Plutonix

+0

il mio codice è in una ClassLibrary caricata da un'applicazione WinForms – plukich

risposta

1

Dal commento originale:

Here's un argomento sulla rimozione di delegati da eventi non si ha la firma del delegato al .. piuttosto comodo, ma alla fine il manifesto ha dichiarato

"Sembra AppDomain.CurrentDomain.AssemblyResolve non supporta la rimozione di eventi a tutti in modo che il codice che ho postato non funzionerà."

Anche .NET lamenta che l'evento System.AppDomain.AssemblyResolve può apparire solo sul lato sinistro della += o -= (+=/-= operatori sono il C# AddHandler/RemoveHandler) .. quindi che sta cercando come un 'no':/

Inoltre, dopo le modifiche, la ragione non è possibile effettuare le seguenti operazioni:

RemoveHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf GetType(Reflection.Assembly).GetMethod("ResolveAssembly") 

è perché la parola AddressOf è una parola chiave operatore, simile ad un + o - essendo un operatore, il AddressOf opera sulla procedura indicata e deve essere un nome di procedura che può dedurre in fase di compilazione. E la funzione GetMethod restituisce un tipo MethodInfo e non un indirizzo di funzione noto.

Tuttavia, non tutto è perduto!

Le funzioni AddHandler e RemoveHandler in realtà richiedono una Object e Delegate da passare a (AddressOf viene compilato in un Delegate se usato), quindi non c'è bisogno del AddressOf di fare ciò che si vuole, è necessario un .

Per fare ciò, è possibile utilizzare il metodo CreateDelegate che fa prendere un oggetto MethodInfo. Va notato che da quando si sta cercando di accedere ai metodi privati, è necessario specificare il BindFlags di Reflection.BindingFlags.Instance e Reflection.BindFlags.NonPublic (dico and ma farò un bit per bit Or su di loro), ad esempio:

GetType(Reflection.Assembly).GetMethod("ResolveAssembly", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic) 

quindi chiamando CreateDelegate su questo ci darà il seguente codice

[Delegate].CreateDelegate(GetType(Reflection.Assembly), GetType(Reflection.Assembly).GetMethod("ResolveAssembly", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic)) 

ma questo è piuttosto prolisso, così lascia abbattere:

Dim type As Type = GetType(Reflection.Assembly) 
Dim mi As Reflection.MethodInfo = type.GetMethod("ResolveAssembly", (Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic)) 

E ora possiamo semplicemente chiamare il RemoveHandler sul AppDomain.CurrentDomain.AssemblyResolve tramite il seguente:

RemoveHandler AppDomain.CurrentDomain.AssemblyResolve, [Delegate].CreateDelegate(type, mi) 

Tranne AppDomain.CurrentDomain.AssemblyResolve aspetta delegare/firme di eventi per abbinare, quindi abbiamo bisogno di gettare il nostro delegato creato per il tipo appropriato:

RemoveHandler AppDomain.CurrentDomain.AssemblyResolve, CType([Delegate].CreateDelegate(type, mi), System.ResolveEventHandler) 

E ora è possibile rimuovere un metodo privato tramite il reflection dal gestore eventi.

ATTENZIONE !! Mentre questo codice verrà compilato ed eseguito, non fornisco alcuna garanzia di validità o accuratezza dato che si tratta di frame e stack pointers (essenzialmente), quindi mentre potrebbe eseguire e potrebbe funzionare, anche potrebbero generare cuccioli di gattini .. quindi basta fare attenzione.

Spero che possa essere d'aiuto!

+0

Grazie txtechhelp :) – raed