2011-08-23 17 views
8

Nella mia applicazione ho usato in precedenza attributi C# regolari per "annotare" un metodo. Es .:Aspetti multipli su un metodo

 

[Foo(SomeKey="A", SomeValue="3")] 
[Foo(SomeKey="B", SomeValue="4")] 
public void TheMethod() 
{ 
    SpecialAttributeLogicHere(); 
} 

 

Che SpecialAttributeLogicHere() ha fatto, è stato a guardare riflessivo a tutti i Foo-attributi che annotati questo particolare metodo. Sarebbe quindi (da solo), creare il proprio dizionario per tutte le chiavi e valori.

Ora sto cercando di passare a PostSharp, perché lo SpecialAttributeLogic potrebbe essere messo in un aspetto (e rimosso dal corpo del metodo che è molto più pulito!), All'interno di OnEntry. Foo sarà sostituito da un aspetto che estende OnMethodBoundaryAspect.

mi piace ancora di utilizzare nel modo seguente:


[Foo(SomeKey="A", SomeValue="3")] 
[Foo(SomeKey="B", SomeValue="4")] 

Ma se Foo ha un OnEntry, che significa che il "SpecialAttributeLogic" verrà eseguito due volte. Fondamentalmente ho bisogno di "raccogliere" tutte le chiavi e i valori da ogni Foo(), in un dizionario, al quale poi applicherò qualche logica.

Come fare questo (o best practice) con PostSharp? Grazie!

+0

aggiunto un esempio di lavoro nella mia risposta di seguito. –

risposta

2

Sembra che tu voglia costruire una maschera namevalue all'interno del tuo metodo. Non puoi farlo con un aspetto. Quello che suggerisco è utilizzare un MethodInterceptionAspect e riflettere gli attributi sul metodo, quindi creare la raccolta e passarla nel metodo tramite un parametro (magari utilizzando un metodo sovraccarico) o impostandolo come membro della classe.

È possibile riflettere i valori in fase di compilazione per mantenere le prestazioni ottimali.

Ecco una soluzione rapida al tuo problema. È un po 'brutto (dovrai apportare modifiche per adattarlo). Ci sono altri modi, ma non sono così "generici".

namespace ConsoleApplication12 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      MyExampleClass ec = new MyExampleClass(); 
      ec.MyMethod(); 
     } 
    } 

    public class MyExampleClass 
    { 
     [Special(Key = "test1", Value = "1234")] 
     [Special(Key = "test2", Value = "4567")] 
     [MyAspect] 
     public void MyMethod() 
     { 
      MyMethod(new Dictionary<string, string>()); 
     } 

     public void MyMethod(Dictionary<string, string> values) 
     { 
      //Do work 
     } 

    } 

    [Serializable] 
    public class MyAspect : MethodInterceptionAspect 
    { 
     Dictionary<string, string> values = new Dictionary<string, string>(); 
     MethodInfo target; 

     public override void CompileTimeInitialize(System.Reflection.MethodBase method, AspectInfo aspectInfo) 
     { 
      target = method.DeclaringType.GetMethod(method.Name, new Type[] { typeof(Dictionary<string, string>) }); 

      foreach (Attribute a in method.GetCustomAttributes(false)) 
      { 
       if (a is SpecialAttribute) 
       { 
        values.Add(((SpecialAttribute)a).Key, ((SpecialAttribute)a).Value); 
       } 
      } 
     } 

     public override void OnInvoke(MethodInterceptionArgs args) 
     { 
      if (values == null || values.Count < 1) 
      { 
       args.Proceed(); 
      } 
      else 
      { 
       target.Invoke(args.Instance, new object[] { values }); 
      } 

     } 
    } 
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true) ] 
    public class SpecialAttribute : Attribute 
    { 
     public string Key { get; set; } 
     public string Value { get; set; } 
    } 
} 

bersaglio e valori sono entrambi inizializzati compiletime (non runtime) per il consumo in fase di esecuzione. Vengono serializzati con l'aspetto al momento dell'ordine. In questo modo risparmi sull'irrazione riflessa in fase di esecuzione.

+0

Buona risposta. In alternativa suppongo di poter fare lo stesso approccio, ma usando OnMethodBoundaryAspect invece di MethodInterceptionAspect. Quindi, in OnEntry vorrei leggere gli attributi per il metodo usando la riflessione. Ma d'altra parte, forse MethodInterceptionAspect è migliore per le mie esigenze. Dovrò pensarci ... –

+1

Sì, puoi farlo, ma il problema è ottenere l'accesso ai dati una volta che li hai colelcati dagli attributi. Non vorrei rendere l'attributo un aspetto perché finirai per avere più aspetti in esecuzione e davvero complicare il tuo codice. Ma usando MethodBoundaryAspect evita il bisogno di un overload di metodi. Quindi in entrambi i casi dovrebbe essere ok. –

0

Proprio come una nota, ho finito per utilizzare MethodInterceptionAspect e solo sovrascrivere OnInvoke. All'interno di OnInvoke ho esaminato args.Method.GetCustomAttributes(), assegnandomi tutti gli Attributi di sistema che ho impostato (ad esempio SpecialAttribute nell'esempio di DustinDavis).

Utilizzando quegli attributi e le loro proprietà, posso eseguire la logica che dovevo eseguire. Se la logica riesce, finisco con args.Proceed(), altrimenti lancio un'eccezione.

Problemi correlati