2011-08-23 11 views
8

En mi aplicación, utilicé previamente atributos de C# regulares para "anotar" un método. Ej .:Aspectos múltiples en un método

 

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

 

Lo SpecialAttributeLogicHere() lo hizo, fue a mirar reflexivamente en todos los Foo-atributos que anotados este método en particular. Entonces (por sí solo), creará su propio diccionario para todas las claves y valores.

Ahora estoy tratando de pasar a PostSharp, porque SpecialAttributeLogic podría ponerse en un aspecto (y eliminarse del cuerpo del método que es mucho más limpio!) Dentro de OnEntry. Foo será reemplazado por un aspecto que amplía OnMethodBoundaryAspect.

todavía me gustaría que utilice de la siguiente manera:


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

Pero si Foo tiene un OnEntry, eso significa que el "SpecialAttributeLogic" se ejecutará dos veces. Básicamente necesito "reunir" todas las claves y valores de cada Foo(), en un diccionario, y luego aplicaré un poco de lógica.

¿Cómo hacer esto (o mejores prácticas) con PostSharp? ¡Gracias!

+0

ejemplo de trabajo agregado en mi respuesta a continuación. –

Respuesta

2

Parece que desea construir un valor de nombre dentro de su método. No puedes hacer esto con un aspecto. Lo que sugiero es que use MethodEnceceptionAspect y que refleje los atributos del método, luego cree su colección y páselo en el método a través de un parámetro (tal vez usando un método sobrecargado) o configurándolo como miembro de la clase.

Puede reflejar los valores en tiempo de compilación para mantener el rendimiento óptimo.

Aquí hay una rápida solución a su problema. Es un poco feo (tendrás que hacer modificaciones para encajar). Hay otras formas, pero no son tan "genéricas".

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; } 
    } 
} 

objetivo y valores se inicializan tanto en tiempo de compilación (no tiempo de ejecución) para el consumo en tiempo de ejecución. Se serializan con el aspecto en tiempo de compilación. De esta forma ahorras en el golpe de reflexión en tiempo de ejecución.

+0

Buena respuesta. Alternativamente, supongo que puedo hacer el mismo enfoque, pero usando OnMethodBoundaryAspect en lugar de MethodInterceptionAspect. Luego, en OnEntry, leería los atributos del método usando reflection. Pero, por otro lado, quizás MethodInterceptionAspect es mejor para mis necesidades. Tendré que pensarlo ... –

+1

Sí, puedes hacerlo, pero el problema es obtener acceso a los datos una vez que los has recogido de los atributos. No convertiría el atributo en un aspecto porque terminarás teniendo múltiples aspectos ejecutándose y realmente complicando tu código. Pero el uso de MethodBoundaryAspect evita la necesidad de una sobrecarga de métodos. Entonces, de cualquier manera, debería estar bien. –

0

Solo como una nota, terminé usando MethodInterceptionAspect y solo anulé OnInvoke. Dentro de OnInvoke miré args.Method.GetCustomAttributes(), dándome todos los atributos del sistema que configuré (es decir, SpecialAttribute en el ejemplo de DustinDavis).

Utilizando esos atributos y sus propiedades, puedo ejecutar la lógica que necesitaba para ejecutar. Si la lógica tiene éxito, termino con args.Proceed(), si no arrojo una excepción.

Cuestiones relacionadas