Example #1
0
        /// <summary>
        /// 重写方法。
        /// </summary>
        /// <param name="instanceAst">方法“this”上下文。</param>
        /// <param name="classEmitter">类。</param>
        /// <param name="methodInfo">被重写的方法。</param>
        /// <param name="attributeDatas">属性。</param>
        public static MethodEmitter DefineMethodOverride(AstExpression instanceAst, ClassEmitter classEmitter, MethodInfo methodInfo, IList <CustomAttributeData> attributeDatas)
        {
            var methodAttributes = methodInfo.Attributes;

            if ((methodAttributes & MethodAttributes.Abstract) == MethodAttributes.Abstract)
            {
                methodAttributes ^= MethodAttributes.Abstract;
            }

            bool flag = true;

            var overrideEmitter = classEmitter.DefineMethodOverride(ref methodInfo, methodAttributes);

            var paramterEmitters = overrideEmitter.GetParameters();

#if NET40
            foreach (var attributeData in attributeDatas.Where(x => InterceptAttributeType.IsAssignableFrom(x.Constructor.DeclaringType)))
#else
            foreach (var attributeData in attributeDatas.Where(x => InterceptAttributeType.IsAssignableFrom(x.AttributeType)))
#endif
            {
                if (flag)
                {
                    flag = false;
                }

                overrideEmitter.SetCustomAttribute(attributeData);
            }

            if (flag && !methodInfo.DeclaringType.IsInterface && !methodInfo.IsDefined(InterceptAttributeType, true))
            {
                overrideEmitter.Append(Call(instanceAst, methodInfo, paramterEmitters));

                return(overrideEmitter);
            }

            AstExpression[] arguments = null;

            var variable = Variable(typeof(object[]));

            overrideEmitter.Append(Assign(variable, Array(paramterEmitters)));

            if (overrideEmitter.IsGenericMethod)
            {
                arguments = new AstExpression[] { Constant(overrideEmitter), instanceAst, Constant(methodInfo), variable };
            }
            else
            {
                var tokenEmitter = classEmitter.DefineField($"____token__{methodInfo.Name}", typeof(MethodInfo), FieldAttributes.Private | FieldAttributes.Static | FieldAttributes.InitOnly);

                classEmitter.TypeInitializer.Append(Assign(tokenEmitter, Constant(methodInfo)));

                var proxyEmitter = classEmitter.DefineField($"____proxy__{methodInfo.Name}", typeof(MethodInfo), FieldAttributes.Private | FieldAttributes.Static | FieldAttributes.InitOnly);

                classEmitter.TypeInitializer.Append(Assign(proxyEmitter, Constant(overrideEmitter)));

                arguments = new AstExpression[] { proxyEmitter, instanceAst, tokenEmitter, variable };
            }

            BlockAst blockAst;

            if (paramterEmitters.Any(x => x.RuntimeType.IsByRef))
            {
                var finallyAst = Block(typeof(void));

                for (int i = 0; i < paramterEmitters.Length; i++)
                {
                    var paramterEmitter = paramterEmitters[i];

                    if (!paramterEmitter.IsByRef)
                    {
                        continue;
                    }

                    finallyAst.Append(Assign(paramterEmitter, Convert(ArrayIndex(variable, i), paramterEmitter.ParameterType)));
                }

                blockAst = Try(methodInfo.ReturnType, finallyAst);
            }
            else
            {
                blockAst = Block(methodInfo.ReturnType);
            }

            if (overrideEmitter.ReturnType.IsClass && typeof(Task).IsAssignableFrom(overrideEmitter.ReturnType))
            {
                if (overrideEmitter.ReturnType.IsGenericType)
                {
                    blockAst.Append(Call(InterceptAsyncGenericMethodCall.MakeGenericMethod(overrideEmitter.ReturnType.GetGenericArguments()), New(InterceptContextCtor, arguments)));
                }
                else
                {
                    blockAst.Append(Call(InterceptAsyncMethodCall, New(InterceptContextCtor, arguments)));
                }
            }
            else if (overrideEmitter.ReturnType == typeof(void))
            {
                blockAst.Append(Call(InterceptMethodCall, New(InterceptContextCtor, arguments)));
            }
            else
            {
                blockAst.Append(Call(InterceptGenericMethodCall.MakeGenericMethod(overrideEmitter.ReturnType), New(InterceptContextCtor, arguments)));
            }

            overrideEmitter.Append(blockAst);

            return(overrideEmitter);
        }