Exemplo n.º 1
0
        /// <summary>
        /// 构建事件
        /// </summary>
        /// <param name="member"></param>
        /// <param name="members"></param>
        /// <param name="exists"></param>
        /// <param name="typeBuilder">类型构建</param>
        /// <param name="sourceTypeOrInterfaceType">假如是承继父类的,则callBase就能生效</param>
        /// <param name="buildInterface">构建接口</param>
        protected virtual void BuildEvent(MemberInfo member, MemberInfo[] members, List <MemberInfo> exists, TypeBuilder typeBuilder, Type sourceTypeOrInterfaceType, bool @buildInterface)
        {
            var @event = member as EventInfo;

            exists.Add(@event);
            var        addName = string.Concat("add_", @event.Name);
            var        removeName = string.Concat("remove_", @event.Name);
            MethodInfo addMethod = null, removeMethod = null;

            foreach (var m in members)
            {
                if (m.MemberType == MemberTypes.Method)
                {
                    if (addName == m.Name)
                    {
                        addMethod = (MethodInfo)m;
                        exists.Add(m);
                        if (removeMethod != null)
                        {
                            break;
                        }
                    }
                    else if (removeName == m.Name)
                    {
                        removeMethod = (MethodInfo)m;
                        exists.Add(m);
                        if (addMethod != null)
                        {
                            break;
                        }
                    }
                }
            }

            FieldBuilder fieldBuilder = null;
            EventBuilder eventBuilder = null;

            if (!@buildInterface && (addMethod == null || addMethod.IsFinal) && (removeMethod == null || removeMethod.IsFinal))
            {
                return;
            }

            eventBuilder = typeBuilder.DefineEvent(@event.Name, @event.Attributes, @event.EventHandlerType);

            if (addMethod != null)
            {
                fieldBuilder = typeBuilder.DefineField(@event.Name, @event.EventHandlerType, FieldAttributes.Private);
                /*泛型方法和基本方法有什么不同*/
                var parameters     = addMethod.GetParameters();
                var parameterTypes = new List <Type>(parameters.Length);
                var voidReturn     = addMethod.ReturnType == typeof(void);

                foreach (var parameter in parameters)
                {
                    parameterTypes.Add(parameter.ParameterType);
                }

                var attributes = MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.SpecialName;
                if (!buildInterface)
                {
                    attributes = MethodAttributes.Public | MethodAttributes.ReuseSlot | MethodAttributes.Virtual | MethodAttributes.HideBySig;
                }

                var methodBuilder = typeBuilder.DefineMethod(addMethod.Name,
                                                             attributes,
                                                             addMethod.CallingConvention,
                                                             addMethod.ReturnType, parameterTypes.ToArray());

                /*fix argument length*/
                parameterTypes.Insert(0, sourceTypeOrInterfaceType);
                var il     = new MockEmitBuilder(methodBuilder.GetILGenerator(), addMethod.CallingConvention, addMethod.ReturnType, parameterTypes.ToArray());
                var locals = new[]
                {
                    il.DeclareLocal(@event.EventHandlerType),
                    il.DeclareLocal(@event.EventHandlerType),
                    il.DeclareLocal(@event.EventHandlerType),
                };
                var label = il.DefineLabel();

                il.LoadArgument(0);
                il.LoadField(fieldBuilder);
                il.StoreLocal(locals[0]);

                il.MarkLabel(label);
                il.LoadLocal(locals[0]);
                il.StoreLocal(locals[1]);
                il.LoadLocal(locals[1]);
                il.LoadArgument(1);

                MethodInfo delegateMethod = null;
                foreach (var method in typeof(System.Delegate).GetMethods(BindingFlags.Public | BindingFlags.Static))
                {
                    if (method.Name == "Combine" && method.GetParameters().Length == 2)
                    {
                        delegateMethod = method;
                        break;
                    }
                }

                il.Call(delegateMethod);
                il.CastClass(@event.EventHandlerType);
                il.StoreLocal(locals[2]);

                il.LoadArgument(0);
                il.LoadFieldAddress(fieldBuilder);
                il.LoadLocal(locals[2]);
                il.LoadLocal(locals[1]);

                foreach (var method in typeof(System.Threading.Interlocked).GetMethods(BindingFlags.Public | BindingFlags.Static))
                {
                    if (method.Name == "CompareExchange" && method.IsGenericMethod && method.GetParameters().Length == 3)
                    {
                        delegateMethod = method;
                        break;
                    }
                }
                il.Call(delegateMethod.MakeGenericMethod(new[] { @event.EventHandlerType }));
                il.StoreLocal(locals[0]);
                il.LoadLocal(locals[0]);
                il.LoadLocal(locals[1]);
                il.UnsignedBranchIfNotEqual(label);
                il.Return();

                @eventBuilder.SetAddOnMethod(methodBuilder);
            }

            if (removeMethod != null)
            {
                if (fieldBuilder == null)
                {
                    fieldBuilder = typeBuilder.DefineField(@event.Name, @event.EventHandlerType, FieldAttributes.Private);
                }

                /*泛型方法和基本方法有什么不同*/
                var parameters     = removeMethod.GetParameters();
                var parameterTypes = new List <Type>(parameters.Length);
                var voidReturn     = removeMethod.ReturnType == typeof(void);

                foreach (var parameter in parameters)
                {
                    parameterTypes.Add(parameter.ParameterType);
                }

                var attributes = MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.SpecialName;
                if (!buildInterface)
                {
                    attributes = MethodAttributes.Public | MethodAttributes.ReuseSlot | MethodAttributes.Virtual | MethodAttributes.HideBySig;
                }

                var methodBuilder = typeBuilder.DefineMethod(removeMethod.Name,
                                                             attributes,
                                                             removeMethod.CallingConvention,
                                                             removeMethod.ReturnType, parameterTypes.ToArray());

                /*fix argument length*/
                parameterTypes.Insert(0, sourceTypeOrInterfaceType);
                var il     = new MockEmitBuilder(methodBuilder.GetILGenerator(), removeMethod.CallingConvention, removeMethod.ReturnType, parameterTypes.ToArray());
                var locals = new[]
                {
                    il.DeclareLocal(@event.EventHandlerType),
                    il.DeclareLocal(@event.EventHandlerType),
                    il.DeclareLocal(@event.EventHandlerType),
                };
                var label = il.DefineLabel();

                il.LoadArgument(0);
                il.LoadField(fieldBuilder);
                il.StoreLocal(locals[0]);

                il.MarkLabel(label);
                il.LoadLocal(locals[0]);
                il.StoreLocal(locals[1]);
                il.LoadLocal(locals[1]);
                il.LoadArgument(1);

                MethodInfo delegateMethod = null;
                foreach (var method in typeof(System.Delegate).GetMethods(BindingFlags.Public | BindingFlags.Static))
                {
                    if (method.Name == "Remove" && method.GetParameters().Length == 2)
                    {
                        delegateMethod = method;
                        break;
                    }
                }

                il.Call(delegateMethod);
                il.CastClass(@event.EventHandlerType);
                il.StoreLocal(locals[2]);

                il.LoadArgument(0);
                il.LoadFieldAddress(fieldBuilder);
                il.LoadLocal(locals[2]);
                il.LoadLocal(locals[1]);

                foreach (var method in typeof(System.Threading.Interlocked).GetMethods(BindingFlags.Public | BindingFlags.Static))
                {
                    if (method.Name == "CompareExchange" && method.IsGenericMethod && method.GetParameters().Length == 3)
                    {
                        delegateMethod = method;
                        break;
                    }
                }
                il.Call(delegateMethod.MakeGenericMethod(new[] { @event.EventHandlerType }));
                il.StoreLocal(locals[0]);
                il.LoadLocal(locals[0]);
                il.LoadLocal(locals[1]);
                il.UnsignedBranchIfNotEqual(label);
                il.Return();

                @eventBuilder.SetRemoveOnMethod(methodBuilder);
            }
        }