Несколько аспектов на один метод - PullRequest
8 голосов
/ 23 августа 2011

В моем приложении я ранее использовал обычные атрибуты 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?Спасибо!

Ответы [ 2 ]

2 голосов
/ 23 августа 2011

Похоже, вы хотите создать пару имен в вашем методе.Вы не можете сделать это с аспектом.Я предлагаю вам использовать метод 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 и значения оба инициализируются во время компиляции (не во время выполнения) для потребления во время выполнения.Они сериализуются с аспектом во время компиляции.Таким образом вы сэкономите на отражении во время выполнения.

0 голосов
/ 24 августа 2011

Так же, как примечание, я в конечном итоге использовал MethodInterceptionAspect и переопределял только OnInvoke.В OnInvoke я посмотрел на args.Method.GetCustomAttributes (), дав мне все установленные мной System.Attributes (т.е. SpecialAttribute в примере DustinDavis).

Используя эти атрибуты и их свойства, я могу запустить логику, необходимую для запуска.Если логика завершается успешно, я заканчиваю с args.Proceed (), если нет, я выкидываю исключение.

...