2015-04-14 15 views
7

Desidero aggiungere una funzione di richiamata comune a tutti i metodi di un oggetto. Ho trovato this SO question ma in quell'approccio dovevo modificare ogni funzione della classe. Vorrei definire qualche metodo beforeFilter che viene troncato prima di ogni chiamata di metodo. So che potrei usare Action delegates per quello ma non so come.Come aggiungere una richiamata a un modulo Web Progetto

UPDATE: Per fare un esempio, quello che voglio sarebbe qualcosa di simile

Class MyClass 

    Sub MyCallback 
     'callback code... 
    End Sub 

    'Rest of tyhe code 

End Class 

Come si può vedere, l'ideale sarebbe di aggiungere un metodo semplice (più di uno o) per ottenere trigered prima di tutto il resto dei metodi. Forse con qualche classe base o un'interfaccia, non lo so (è per questo che chiedo).

Un'altra opzione che penso possa essere possibile è quella di clonare l'oggetto e definire una nuova classe invece di aggiungere codice a quello esistente. Quindi, in questo Class utilizzare il Object per ottenere l'accesso ai metodi trhough la Type

Class NewClass 

    Sub AddCallback(Obj As Object, Callback As Action) 
      'Add the callback here 
    End Sub 
End Class 

sto solo indovinare, magari un po 'della mia opzione sono anche impraticabile, quindi si prega di aiutare la mia su questo

più vicino avvicinarsi

Quello che ho per ora, è questo metodo

Sub RunWithCallback(beforFilter As Action, f As Action) 

    beforeFilter() 
    f() 

End Sub 

(Ciò significa un sacco di sovraccarichi per il RunWithCallback per gestire Sub e Funzioni con i delegati Action e Func s, con un numero diverso di parametri) Per utilizzare questo, dovrei eseguire questo Sub invece di chiamare uno dei metodi Object (passando il parametro ByRef per recuperare il valore di ritorno nelle funzioni). Qualcosa di simile

Public Sub DoNothing() 
    Debug.WriteLine("Callback working!") 
End Sub 

Public Sub BeforeFilter() 
    Debug.WriteLine("Testing callback...") 
End Sub 

'To run the above function  
RunWithCallback(AddressOf BeforeFilter, AddressOf DoNothing) 

penso che ci dovrebbe essere una soluzione migliore a questo, cosa che permette di evitare di chiamare lo stesso sub, ed evitare i sovraccarichi, una sorta di metodo di estensione dinamica per l'oggetto Class

+0

Alcuni codici di esempio potrebbero essere utili, così come è molto poco chiaro quello che vuoi.Ad esempio, si suppone che 'beforeFilter' venga chiamato prima del metodo è invocato o at inizia di ogni metodo? Un delegato di 'Action' richiederà comunque il refactoring, quindi non sembra che sia quello che vuoi. – Plutonix

+0

Controlla la mia modifica, se hai ancora dubbi, commenta di nuovo. –

+0

Se 'MyCallback' è in' MyClass' e invocato da 'MyClass' perché la classe non è in grado di invocarlo (non è come un 'callback'). È più comune usare un delegato (non necessariamente 'Action') quando un metodo * non * ha accesso a un metodo che si desidera utilizzare * da qualche altra parte *. Ad esempio, 'ClassA.DoFoo' è invocato da ClassB e nel corso di' DoFoo' è necessario richiamare 'ClassB.GetBar'. – Plutonix

risposta

1

Ecco un esempio di come i delegati funzionano e come u può usare:

public class MyClass 
{ 
    // MyDelegate callback holder 
    private MyDelegate _myDelegate; 

    // Singleton holder 
    private static volatile MyClass _instance; 

    ///<summary> 
    /// Instance property 
    ///</summary> 
    public static MyClass Instance 
    { 
     get 
     { 
      if (_instance == null) 
      { 
       _instance = new MyClass(); 
      } 
      _instance.MyCallbacks(_instance.MyDelegateCallback, _instance.MyDelegateCallback1); 
      return _instance; 
     } 
    } 

    ///<summary> 
    /// Instance multi-callback caller 
    ///</summary> 
    ///<param name="callbacks">calbacks to call</param> 
    ///<returns>MyClass</returns> 
    public static MyClass Instance(params MyDelegate[] callbacks) 
    { 
     if (_instance == null) 
     { 
      _instance = new MyClass(); 
     } 
     _instance.MyCallbacks(callbacks); 
     return _instance; 
    } 

    ///<summary> 
    /// MyClass constructor 
    ///</summary> 
    private MyClass() 
    { 
     // Define the callback 
     MyDelegate = MyDelegateCallback; 
    } 

    ///<summary> 
    /// MyDelegate property, here u can change the callback to any function which matches the structure of MyDelegate 
    ///</summary> 
    public MyDelegate MyDelegate 
    { 
     get 
     { 
      return _myDelegate; 
     } 
     set 
     { 
      _myDelegate = value; 
     } 
    } 

    ///<summary> 
    /// Call all given callbacks 
    ///</summary> 
    ///<param name="callbacks">callbacks u want to call</param> 
    public void MyCallbacks(params MyDelegate[] callbacks) 
    { 
     if (callbacks != null) 
     { 
      foreach (MyDelegate callback in callbacks) 
      { 
       if (callback != null) 
       { 
        callback.Invoke(null); 
       } 
      } 
     } 
    } 

    ///<summary> 
    /// RunTest, if u call this method the defined callback will be raised 
    ///</summary> 
    public void RunTest() 
    { 
     if (_myDelegate != null) 
     { 
      _myDelegate.Invoke("test"); 
     } 
    } 

    ///<summary> 
    /// MyDelegateCallback, the callback we want to raise 
    ///</summary> 
    ///<param name="obj"></param> 
    private void MyDelegateCallback(object obj) 
    { 
     System.Windows.MessageBox.Show("Delegate callback called!"); 
    } 

    ///<summary> 
    /// MyDelegateCallback1, the callback we want to raise 
    ///</summary> 
    ///<param name="obj"></param> 
    private void MyDelegateCallback1(object obj) 
    { 
     System.Windows.MessageBox.Show("Delegate callback (1) called!"); 
    } 
} 

///<summary> 
/// MyDelegate, the delegate function 
///</summary> 
///<param name="obj"></param> 
public delegate void MyDelegate(object obj); 

ho aggiornato la mia risposta, uno sguardo ai MyCallbacks(params MyDelegate[] callbacks). Chiamerà diversi callback che corrispondono alla struttura di MyDelegate.
Modifica:
Aggiunto MyClass.Instance & MyClass.Instance(params MyDelegate[] callbacks).

+0

Nella tua risposta, posso vedere che puoi gestire diverse strutture di callback, ma come chiamerebbero questi callback prima del resto dei metodi di classe? –

+0

Ho modificato la mia risposta, ho aggiunto 'MyClass.Instance'. Nel metodo "get" ho aggiunto 'MyCallbacks (params MyDelegate [] callbacks)' con 2 callback di test. Per tutto il tempo che devi chiamare un metodo, chiamalo come 'MyClass.Instance.MyMethodToCall()' perché per tutto il tempo che chiami 'MyClass.Instance' verranno richiamati i callback definiti. - Penso che non ci sia una soluzione migliore. - Tranne che, aggiungi le 'MyCallbacks (params MyDelegate [] callbacks)' con i callback necessari per ogni metodo che hai attualmente. – k1ll3r8e

+0

2nd edit, ho aggiunto ulteriori 'MyClass.Instance (params MyDelegate [] callbacks)' così puoi anche chiamare callback speciali se necessario. – k1ll3r8e

1

Hai mai pensato di utilizzare una libreria Aspect? Fino alla tua domanda sembra davvero che tu possa risolvere il tuo problema con questo approccio.

Ad esempio, è possibile utilizzare il PostSharp library qui, semplicemente derivare la OnMethodBoundaryAspect class, e gestire i quattro disponibili eventi principali:

o due supplementari:

  • onResume
  • OnYield

o uno di essi. La semplice schema è questo:

int MyMethod(object arg0, int arg1) 
{ 
    OnEntry(); 
    try 
    { 
     // YOUR CODE HERE 
     OnSuccess(); 
     return returnValue; 
    } 
    catch (Exception e) 
    { 
     OnException(); 
    } 
    finally 
    { 
     OnExit(); 
    } 
} 

Così si può facilmente richiamare la funzione Callback (e si può estrarre i parametri di runtime-passata in OnSuccess metodo:

public override void OnSuccess(MethodExecutionArgs args) 
{ 
    CallBack(GetValueYouNeed(args)); 
} 

Semplice versione PostSharp è una licenza libera distribuito e ben documentato, quindi ti consiglio caldamente di investigare su questo approccio

+0

Sembra promettente, ma non ha funzionato per me. Ho ereditato la classe menzionata, sovrascrivendo il metodo 'OnEntry' e non è successo niente ... il metodo non è stato attivato automaticamente. Forse sto facendo qualcosa di sbagliato. –

+0

Per quanto mi ricordo, devi aggiungere un evento post build per PostSharp fare il wrapping – VMAtm