一种方法的多个方面

时间:2011-08-23 15:02:24

标签: c# aop postsharp

在我的应用程序中,我以前使用常规的C#属性来“注释”一个方法。 E.g:


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


SpecialAttributeLogicHere()所做的是反思地查看注释了这种特定方法的所有Foo属性。然后(单独),为所有键和值创建自己的字典。

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

我仍然希望以下列方式使用它:


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

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

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

2 个答案:

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

目标和值都在编译时(不是运行时)初始化,以便在运行时使用。它们在编译时被序列化。这样就可以节省运行时的反射效果。

答案 1 :(得分:0)

就像说明一样,我最终使用了MethodInterceptionAspect并且仅重写了OnInvoke。在OnInvoke中,我查看了args.Method.GetCustomAttributes(),给了我设置的所有System.Attributes(即DustinDavis示例中的SpecialAttribute)。

使用这些属性及其属性,我可以运行运行所需的逻辑。如果逻辑成功,我用args.Proceed()完成,如果不是,我抛出异常。