Sparare un evento / funzione su una proprietà? (C #)

Sto usando una class che non posso modificare, ha una proprietà (un booleano) di cui sarebbe bello essere informato quando cambia, non posso modificare le proprietà get o set mentre sto importando la class da a. dll (che non ho il codice per).

Come posso creare un evento / funzione che viene triggersto quando la proprietà viene modificata?

addizionale
Viene modificato solo all’interno della propria class, direttamente nella variabile privata sottostante.

Per esempio

private bool m_MyValue = false; public bool MyValue { get { return m_MyValue; } } private void SomeFunction() { m_MyValue = true; } 

Non puoi, fondamentalmente … non senza usare qualcosa come l’API del debugger per iniettare il codice al momento dell’esecuzione e modificare l’IL della libreria originale (e non sto raccomandando nessuna di queste soluzioni, a parte qualsiasi altra cosa potrebbe violare la licenza della biblioteca).

Fondamentalmente se una proprietà non supporta la notifica, non supporta la notifica. Dovresti cercare un modo diverso di affrontare il tuo problema. (Il polling funzionerebbe, per esempio?)

Non puoi farlo direttamente [come ha detto Jon Skeet], a meno che non sia virtuale, sei in grado di intercettare tutte le creazioni di istanza della class e non ci sono cambiamenti in un campo di supporto che influenza il vero ‘valore’ del prople.

L’unico modo per forzare la forza è usare Mono.Cecil o MS CCI per strumentare il prop setter a questo DimeCast su Cecil . (O PostSharp)

Tuttavia questo non intrappolerebbe le modifiche interne al campo di supporto (se ce n’è anche uno). (Questo è il motivo per cui il wrapping probabilmente non funzionerà).

AGGIORNAMENTO: Dato il tuo aggiornamento che stai sicuramente cercando di intrappolare la modifica del campo sottostante, l’unico modo per farlo è usare PS / CCI / Cecil e analizzare il stream per intercettare tutti gli aggiornamenti sul campo. In breve, non molto fattibile.

Probabilmente, l’unico vero modo per farlo è creare un qualche tipo di componente “watcher”, eseguito in un thread separato, il cui compito è leggere la proprietà a intervalli e generare un evento quando il valore della proprietà cambia. Naturalmente questa soluzione naviga nelle acque torbide del threading e della sincronizzazione.

Partendo dal presupposto che l’applicazione è a thread singolo rispetto a questo object, la soluzione più pulita è quella di effettuare chiamate di metodo a questo object tramite un object proxy. Avrebbe il compito di controllare lo stato prima e dopo la proprietà e di innalzare un evento nel caso in cui fosse cambiato.

Ecco un semplice esempio di ciò di cui sto parlando:

 public class SomeProxy { public SomeProxy(ExternalObject obj) { _obj = obj; } public event EventArgs PropertyChanged; private bool _lastValue; private ExternalObject _obj; protected virtual void OnPropertyChanged() { if(PropertyChanged != null) PropertyChanged(); } protected virtual void PreMethodCall() { _lastValue = _obj.SomeProperty; } protected virtual void PostMethodCall() { if(_lastValue != _obj.SomeProperty) OnPropertyChanged(); } // Proxy method. public SomeMethod(int arg) { PreMethodCall(); _obj.SomeMethod(arg); // Call actual method. PostMethodCall(); } } 

Ovviamente è ansible creare questo modello di proxy in un object adatto – è sufficiente essere consapevoli che tutte le chiamate devono passare attraverso il proxy per l’evento da sollevare quando ci si aspetta che sia.

Come accennato in precedenza, il metodo più diretto (e quello che richiede la minima modifica al codice) consiste nell’utilizzare una libreria AOP come PostSharp.

Tuttavia, è ansible ottenere una soluzione utilizzando il tradizionale C # /. NET utilizzando il modello di proprietà di dipendenza , utilizzato throughtout WPF con grande effetto. Vi suggerisco di leggere su questo, e prendere in considerazione l’implementazione di un tale sistema (o almeno una versione semplificata di esso) per il vostro progetto, se appropriato.

Dovrai creare una class che avvolga la class nella dll, all’interno della proprietà setter basta generare un evento usando i metodi normali.

Potresti ereditare dalla class e hide la proprietà? Qualcosa come questo…

 class MyClass : BaseClass { // hide base property. public new bool MyProperty { get { return base.MyProperty; } set { base.MyProperty = value; RaiseMyPropertyChangedEvent(); } } } 

Penso che l’idea di Alex di un wrapper sia buona, tuttavia, dato che la cosa più importante per te è che tu sappia che il valore è cambiato prima dell’uso , potresti semplicemente spostare la notifica al getter, aggirare le preoccupazioni del cambiamento di valore interno . In questo modo ottieni qualcosa di simile al polling, ma affidabile:

 class MyClass : BaseClass { //local value private bool local; //first access yet? private bool accessed = false; // Override base property. public new bool MyProperty { get { if(!accessed) { // modify first-get case according to your taste, eg local = base.MyProperty; accessed = true; RaiseMyPropertyChangedBeforeUseEvent(); } else { if(local != base.MyProperty) { local = base.MyProperty; RaiseMyPropertyChangedBeforeUseEvent(); } } return local; } set { base.MyProperty = value; } } } 

Puoi provare ad ereditarlo e usarlo al posto del bambino. Sostituisci il “set” della proprietà in modo che sollevi l’evento.

EDIT: … solo se la proprietà è virtuale nella class genitore …