Сложность 300-400
Описание проблемы
Уже много чего написал насчет PostSharp, конкретных решений, кастом компонентов, общие принципы работы. Однако с выходом .Net 4.5 появилась новая фича со специальными словами async\await которые позволяют более просто и компактно описывать асинхронное поведение методов. Новый функционал хорош, но добавляет головной боли при использовании PostSharp, с методами помеченными async, использование классических аспектов не пройдет. Методы с маркером async разворачиваются в машину состояний, что не очень хорошо с точки зрения применения аспектов. Т.е. возьмем стандартную реализацию аспекта трассировщика с помощью PostSharp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
[Serializable] public class TraceAttribute : OnMethodBoundaryAspect { public override void OnEntry(MethodExecutionArgs args) { var methodName = GetMethodName(args.Method); args.MethodExecutionTag = methodName; Console.WriteLine("Entering {0}", methodName); base.OnEntry(args); } public override void OnSuccess(MethodExecutionArgs args) { Console.WriteLine("{0} executed successfully", args.MethodExecutionTag); base.OnSuccess(args); } public override void OnException(MethodExecutionArgs args) { Console.WriteLine("{0} excepted : {1}", args.MethodExecutionTag, args.Exception); base.OnException(args); } private string GetMethodName(MethodBase method) { if (method.IsGenericMethod) { var genericArgs = method.GetGenericArguments(); var typeNames = genericArgs.Select(t => t.Name); return string.Format("{0}<{1}>", method.Name, String.Join(",", typeNames)); } return method.Name; } } |
И применим его к тестовому примеру с вызовом синхронных и асинхронных методов с исключениями и без:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
internal class Program { private static void Main(string[] args) { Start().Wait(); Console.WriteLine("All done"); Console.ReadKey(); } private static async Task Start() { FirstSync(); await SecondAsync(); AsyncVoidThird(); try { ForthSync(); } catch {} try { await FithAsync(); } catch {} } [Trace] private static void FirstSync() {} [Trace] private static void ForthSync() { throw new Exception("boom!"); } [Trace] private static async void AsyncVoidThird() { await Task.Delay(1000); Console.WriteLine("AsyncVoidThird done."); } [Trace] private static async Task SecondAsync() { await Task.Delay(1000); Console.WriteLine("SecondAsync done."); } [Trace] private static async Task FithAsync() { await Task.Delay(1000); throw new Exception("async boom!"); } } |
Результат выполнения программы представлен ниже, и для большей наглядности я разукрасил выводы для каждого метода.