private void InterceptMethods(Builder builder, IEnumerable <BuilderType> attributes)
        {
            if (!attributes.Any())
            {
                return;
            }

            var stopwatch = Stopwatch.StartNew();

            var iMethodInterceptor            = new __IMethodInterceptor(builder);
            var asyncTaskMethodBuilder        = new __AsyncTaskMethodBuilder(builder);
            var asyncTaskMethodBuilderGeneric = new __AsyncTaskMethodBuilder_1(builder);
            var syncRoot  = new __ISyncRoot(builder);
            var task      = new __Task(builder);
            var exception = new __Exception(builder);

            var methods = builder
                          .FindMethodsByAttributes(attributes)
                          .GroupBy(x => new MethodKey(x.Method, x.AsyncMethod))
                          .Select(x => new MethodBuilderInfo(x.Key, x.Select(y => new MethodBuilderInfoItem(y, iMethodInterceptor))))
                          .ToArray();

            foreach (var method in methods)
            {
                this.LogInfo($"Implementing interceptors in method {method.Key.Method}");

                var targetedMethod   = method.Key.AsyncMethod == null ? method.Key.Method : method.Key.AsyncMethod;
                var attributedMethod = method.Key.Method;

                method.AddThisReferenceToAsyncMethod();

                var typeInstance     = method.GetAsyncMethodTypeInstace();
                var interceptorField = new Field[method.Item.Length];

                if (method.RequiresSyncRootField)
                {
                    foreach (var ctors in targetedMethod.DeclaringType.GetRelevantConstructors())
                    {
                        ctors.NewCode().Assign(method.SyncRoot).NewObj(builder.GetType(typeof(object)).Import().ParameterlessContructor).Insert(InsertionPosition.Beginning);
                    }
                }

                targetedMethod
                .NewCode()
                .Context(x =>
                {
                    for (int i = 0; i < method.Item.Length; i++)
                    {
                        var item            = method.Item[i];
                        var name            = $"<{targetedMethod.Name}>_attrib{i}_{item.Attribute.Identification}";
                        interceptorField[i] = targetedMethod.DeclaringType.CreateField(targetedMethod.Modifiers.GetPrivate(), item.Interface.Type, name);

                        x.Load(interceptorField[i]).IsNull().Then(y =>
                        {
                            y.Assign(interceptorField[i]).NewObj(item.Attribute);
                            if (item.HasSyncRootInterface)
                            {
                                y.Load(interceptorField[i]).As(syncRoot.Type).Call(syncRoot.SyncRoot, method.SyncRoot);
                            }
                        });
                        item.Attribute.Remove();
                    }
                })
                .Try(x =>
                {
                    for (int i = 0; i < method.Item.Length; i++)
                    {
                        var item = method.Item[i];
                        x.Load(interceptorField[i]).As(item.Interface.Type).Call(item.Interface.OnEnter, attributedMethod.DeclaringType, typeInstance, attributedMethod, x.GetParametersArray());
                    }

                    x.OriginalBody();

                    // Special case for async methods
                    if (method.Key.AsyncMethod != null && method.Key.Method.ReturnType.Fullname == task.Type.Fullname)     // Task return
                    {
                        var exceptionVar = x.CreateVariable(exception.Type);

                        x.Assign(exceptionVar).Set(
                            x.NewCode().Call(method.Key.AsyncMethod.DeclaringType.GetField("<>t__builder"), asyncTaskMethodBuilder.GetTask)
                            .Call(task.GetException));

                        x.Load(exceptionVar).IsNotNull().Then(y =>
                        {
                            for (int i = 0; i < method.Item.Length; i++)
                            {
                                y.Load(interceptorField[i]).Callvirt(method.Item[i].Interface.OnException, exceptionVar);
                            }
                        });
                    }
                    else if (method.Key.AsyncMethod != null)     // Task<> return
                    {
                        var exceptionVar = x.CreateVariable(exception.Type);
                        var taskArgument = method.Key.Method.ReturnType.GetGenericArgument(0);

                        x.Assign(exceptionVar).Set(
                            x.NewCode().Call(method.Key.AsyncMethod.DeclaringType.GetField("<>t__builder"), asyncTaskMethodBuilderGeneric.GetTask.MakeGeneric(taskArgument))
                            .Call(task.GetException));

                        x.Load(exceptionVar).IsNotNull().Then(y =>
                        {
                            for (int i = 0; i < method.Item.Length; i++)
                            {
                                y.Load(interceptorField[i]).Callvirt(method.Item[i].Interface.OnException, exceptionVar);
                            }
                        });
                    }
                })
                .Catch(exception.Type, x =>
                {
                    if (method.Key.AsyncMethod == null)
                    {
                        for (int i = 0; i < method.Item.Length; i++)
                        {
                            x.Load(interceptorField[i]).As(method.Item[i].Interface.Type).Call(method.Item[i].Interface.OnException, x.Exception);
                        }
                    }

                    x.Rethrow();
                })
                .Finally(x =>
                {
                    for (int i = 0; i < method.Item.Length; i++)
                    {
                        x.Load(interceptorField[i]).As(method.Item[i].Interface.Type).Call(method.Item[i].Interface.OnExit);
                    }
                })
                .EndTry()
                .Return()
                .Replace();
            }
            ;

            stopwatch.Stop();
            this.LogInfo($"Implementing method interceptors took {stopwatch.Elapsed.TotalMilliseconds}ms");
        }
Пример #2
0
 public MethodBuilderInfoItem(AttributedMethod attribute, __IMethodInterceptor @interface)
 {
     this.Attribute            = attribute;
     this.Interface            = @interface;
     this.HasSyncRootInterface = attribute.Attribute.Type.Implements(__ISyncRoot.TypeName);
 }