【问题标题】:Multiple aspects on one method一种方法的多个方面
【发布时间】:2011-11-02 01:16:15
【问题描述】:

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

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

SpecialAttributeLogicHere() 所做的是反思性地查看注释此特定方法的所有 Foo 属性。然后它将(自行)为所有键和值创建自己的字典。

我现在正尝试转移到 PostSharp,因为可以将 SpecialAttributeLogic 放入一个方面(并从更简洁的方法主体中删除!),在 OnEntry 中。 Foo 将替换为扩展 OnMethodBoundaryAspect 的方面。

我还是想通过以下方式使用它:


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

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

如何使用 PostSharp 做到这一点(或最佳实践)?谢谢!

【问题讨论】:

  • 在我下面的答案中添加了工作示例。

标签: c# aop postsharp


【解决方案1】:

请注意,我最终使用了 MethodInterceptionAspect 并且只覆盖了 OnInvoke。在 OnInvoke 中,我查看了 args.Method.GetCustomAttributes(),给出了我设置的所有 System.Attributes(即 DustinDavis 示例中的 SpecialAttribute)。

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

【讨论】:

    【解决方案2】:

    您似乎想在您的方法中构建一个名称值对。你不能用一个方面来做到这一点。我建议您使用 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; }
        }
    }
    

    target 和 values 都在编译时(而不是运行时)初始化,以便在运行时使用。它们在编译时与方面进行序列化。这样可以节省运行时的反射命中。

    【讨论】:

    • 好答案。或者,我想我可以做同样的方法,但使用 OnMethodBoundaryAspect 而不是 MethodInterceptionAspect。然后,在 OnEntry 中,我将使用反射读取该方法的属性。但另一方面,也许 MethodInterceptionAspect 更适合我的需求。我得考虑一下……
    • 是的,您可以这样做,但问题是一旦您从属性中收集了数据,就可以访问数据。我不会将属性作为一个方面,因为您最终会执行多个方面并使您的代码真正复杂化。但是使用 MethodBoundaryAspect 可以避免方法重载。所以无论哪种方式都应该没问题。
    猜你喜欢
    • 2023-03-17
    • 1970-01-01
    • 2011-12-10
    • 2017-12-21
    • 2014-03-25
    • 1970-01-01
    • 1970-01-01
    • 2014-06-23
    • 1970-01-01
    相关资源
    最近更新 更多