2011-08-23 38 views
8

在我的应用程序中,我以前使用常规的C#属性来“注释”一种方法。例如: -一种方法的多个方面

 

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

 

什么SpecialAttributeLogicHere()一样,是要反思一下所有注释这种特殊的方法美孚的属性。然后它会自行为所有键和值创建自己的字典。

我现在正在尝试移动到PostSharp,因为在OnEntry中,SpecialAttributeLogic可以放入一个方面(并且从方法体中移除更清洁!)。 Foo将被一个扩展OnMethodBoundaryAspect的方面所取代。

我仍然想使用它的方式如下:


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

但是,这意味着,如果美孚拥有OnEntry,认为“SpecialAttributeLogic”将被执行两次。我基本上需要将每个Foo()中的所有键和值“收集”到一个字典中,然后我应用一些逻辑。

如何使用PostSharp完成此操作(或最佳实践)?谢谢!

+0

在我的回答下面添加了工作示例。 –

回答

2

它看起来像你想在你的方法内建立一个namevaluepair。你无法做到这一点。我建议您使用MethodInterceptionAspect并反映方法的属性,然后构建您的集合,并通过参数(可能使用重载方法)将其传递给方法,或将其设置为类成员。

您可以在编译时反映这些值,以保持性能最佳。

这是您的问题的快速解决方案。这有点难看(你需要修改以适应)。还有其他方法,但它们不是“通用的”。

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

目标和值都在编译时初始化(不是运行时),以便在运行时消耗。它们在编译时序列化。这样可以节省运行时反射命中。

+0

很好的答案。另外,我想我可以做同样的方法,但使用OnMethodBoundaryAspect而不是MethodInterceptionAspect。然后,在OnEntry中,我将使用反射读取该方法的属性。但另一方面,也许MethodInterceptionAspect更适合我的需求。我必须给它一些想法... –

+1

是的,你可以做到这一点,但问题是一旦你从属性中获取数据,就可以访问数据。我不想让属性成为一个方面,因为你最终会执行多个方面,并且使代码复杂化。但是使用MethodBoundaryAspect可以防止需要重载方法。所以无论哪种方式都应该可以。 –

0

就像一个笔记,我结束了使用MethodInterceptionAspect和只覆盖OnInvoke。在OnInvoke中,我查看了args.Method.GetCustomAttributes(),给了我所设置的所有System.Attributes(即DustinDavis的示例中的SpecialAttribute)。

使用这些属性及其属性,我可以运行我需要运行的逻辑。如果逻辑成功,我用args.Proceed()结束,如果没有,我抛出一个异常。