2009-04-17 10 views
6

Quindi, quello che sto cercando di fare è chiamare una singola funzione propertyWasSet() quando viene impostata qualsiasi proprietà all'interno di una classe C# (al contrario, propertyWasGot() quando è richiesta). Mi piacerebbe anche sapere quale "get" della proprietà è stato invocato.C'è un modo per chiamare un metodo quando viene impostata una proprietà di una classe?

Vorrei mantenere un dictonary di proprietà che sono 'set' e controllare l'azione 'get' se sono state ancora impostate (e lanciare un errore se non lo è stato).

Sto osservando la documentazione di msdn per la riflessione, i delegati, ecc., Ma non sono del tutto sicuro che ciò sia possibile.

C'è un modo per farlo? o lanciare un evento chiamando una di queste funzioni che può essere intercettata in una classe base o qualcosa del genere?

risposta

0

Penso che quello che ti serve sia molto simile al sistema di proprietà di dipendenza WPF. Potresti voler dare un'occhiata alla sua implementazione. In ogni caso, è possibile aggiungere il codice di intercettazione a getter e setter di ogni proprietà.

+0

sì, sto cercando di evitare di aggiungere il controllo di ogni proprietà in quanto ce ne sono diversi, e il codice è quasi lo stesso per ciascuno. –

3

Si consiglia di esaminare PostSharp per questo tipo di attività. È progettato per funzionare su C# (o qualsiasi linguaggio .NET per quella materia) e ha il vantaggio di non ingombrare il codice con la riflessione in aggiunta. In effetti, non credo che potresti trovare una soluzione che utilizza C#/Reflection senza aggiungere manualmente il codice a ciascuna delle tue proprietà, quindi consiglierei PostSharp come la strada da percorrere.

0

Non c'è niente di simile se non lo crei da solo.

+0

Ho preso in considerazione la creazione di una nuova classe in fase di esecuzione e il wrapping di tutte le proprietà della classe in un metodo che fa le cose, quindi si occupa delle normali attività commerciali, ma ancora una volta, non sono sicuro che sia possibile e si complichi rapidamente. –

7

Ho scritto un intercettatore l'altra settimana per Set che può essere facilmente esteso per Get, utilizza RealProxy, il che significa che la classe base deve derivare da MarshalByRefObject.

Un'altra opzione di fantasia consiste nell'avere estratto la classe e utilizzare Reflection Emit per creare una classe concreta che racchiuda tutte le proprietà.

Inoltre si poteva guardare generatori di codice per aggirare questo o PostSharp ...

prestazioni per questa soluzione non è stellare, ma dovrebbe essere molto veloce per la maggior parte vincolante UI. Potrebbe essere migliorato generando metodi LCG per l'invocazione del proxy.

public interface IInterceptorNotifiable { 
    void OnPropertyChanged(string propertyName); 
} 

/// <summary> 
/// A simple RealProxy based property interceptor 
/// Will call OnPropertyChanged whenever and property on the child object is changed 
/// </summary> 
public class Interceptor<T> where T : MarshalByRefObject, IInterceptorNotifiable, new() { 

    class InterceptorProxy : RealProxy { 
     T proxy; 
     T target; 
     EventHandler<PropertyChangedEventArgs> OnPropertyChanged; 

     public InterceptorProxy(T target) 
      : base(typeof(T)) { 
      this.target = target; 
     } 

     public override object GetTransparentProxy() { 
      proxy = (T)base.GetTransparentProxy(); 
      return proxy; 
     } 


     public override IMessage Invoke(IMessage msg) { 

      IMethodCallMessage call = msg as IMethodCallMessage; 
      if (call != null) { 

       var result = InvokeMethod(call); 
       if (call.MethodName.StartsWith("set_")) { 
        string propName = call.MethodName.Substring(4); 
        target.OnPropertyChanged(propName); 
       } 
       return result; 
      } else { 
       throw new NotSupportedException(); 
      } 
     } 

     IMethodReturnMessage InvokeMethod(IMethodCallMessage callMsg) { 
      return RemotingServices.ExecuteMessage(target, callMsg); 
     } 

    } 

    public static T Create() { 
     var interceptor = new InterceptorProxy(new T()); 
     return (T)interceptor.GetTransparentProxy(); 
    } 


    private Interceptor() { 
    } 

} 

Usage:

class Foo : MarshalByRefObject, IInterceptorNotifiable { 
     public int PublicProp { get; set; } 
     public string lastPropertyChanged; 

     public void OnPropertyChanged(string propertyName) { 
      lastPropertyChanged = propertyName; 
     } 

    } 


    [Test] 
    public void TestPropertyInterception() { 

     var foo = Interceptor<Foo>.Create(); 
     foo.PublicProp = 100; 

     Assert.AreEqual("PublicProp", foo.lastPropertyChanged); 

    } 
} 
+0

questo è davvero interessante. Presumo che potrei fare la roba Create() all'interno del costruttore dell'oggetto, quindi non dovrei modificare esplicitamente l'istanza di tutti i miei oggetti. Ho intenzione di giocare con questo. Grazie mille! –

+0

Penso che avrai davvero bisogno di una fabbrica per i tuoi oggetti, che può comunque essere una pratica migliore (dato che ti permette di scambiare implementazioni di oggetti in una data successiva e memorizzare istanze di oggetti) –

0

SET parte della richiesta è molto simile al sistema di proprietà di dipendenza WPF. Ma la parte GET è così insolita che manca anche nel sistema di proprietà di dipendenza WPF!

Problemi correlati