/// <summary> /// 构建构造函数【用于代理类】,因为IoC注入和Proxy使用的方式是不同的,Proxy可能直接用数组去构造,而IoC只能一个一个去注入 /// </summary> /// <param name="typeBuilder">类型构造</param> /// <param name="sourceTypeOrInterfaceType">代理(接口或类)类型</param> /// <param name="interceptors">拦截器集合</param> /// <param name="interceptorFieldBuilder">拦截器构建,被定义为List接口</param> protected override void DefineConstructor(TypeBuilder typeBuilder, Type sourceTypeOrInterfaceType, Type[] interceptors, FieldBuilder interceptorFieldBuilder) { /*构造函数*/ var ctorParamters = new List <Type>(1) { typeof(IInterceptor[]) }; var ctorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, ctorParamters.ToArray()); /*fix argument length*/ ctorParamters.Insert(0, sourceTypeOrInterfaceType); var ctorIL = new MockEmitBuilder(ctorBuilder.GetILGenerator(), ctorBuilder.CallingConvention, typeof(void), ctorParamters.ToArray()); ctorIL.LoadArgument(0); ctorIL.LoadConstant(2); ctorIL.NewObject(typeof(List <IInterceptor>).GetConstructor(new[] { typeof(int) })); ctorIL.StoreField(interceptorFieldBuilder); ctorIL.LoadArgument(0); ctorIL.LoadField(interceptorFieldBuilder); ctorIL.LoadArgument(1); ctorIL.Call(typeof(List <IInterceptor>).GetMethod("AddRange", new[] { typeof(IInterceptor[]) })); ctorIL.Return(); }
/// <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> /// <param name="found"></param> private void BuildMethod(MemberInfo member, MemberInfo[] members, List <MemberInfo> exists, TypeBuilder typeBuilder, Type sourceTypeOrInterfaceType, bool @buildInterface, MockSetup found) { var method = member as MethodInfo; if (!@buildInterface && method.IsFinal) { return; } /*泛型方法和基本方法有什么不同*/ var parameters = method.GetParameters(); var parameterTypes = new List <Type>(parameters.Length); var voidReturn = method.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(method.Name, attributes, method.CallingConvention, method.ReturnType, parameterTypes.ToArray()); /*fix argument length*/ parameterTypes.Insert(0, sourceTypeOrInterfaceType); var il = new MockEmitBuilder(methodBuilder.GetILGenerator(), method.CallingConvention, method.ReturnType, parameterTypes.ToArray()); if (found == null) { goto _notImpl; } goto _impl; _notImpl: { if (voidReturn) { /*out 参数*/ for (var i = 0; i < parameters.Length; i++) { if (parameters[i].IsOut) { il.LoadArgument((ushort)(i + 1)); var ele = parameters[i].ParameterType.GetElementType(); if (ele.IsValueType) { if (this.IsEnumType(ele) || this.IsNullableEnumType(ele)) { il.Call(typeof(MockSetupInfoStore).GetMethod("ReturnDefault").MakeGenericMethod(new[] { ele })); il.StoreIndirect(Enum.GetUnderlyingType(ele)); } else { il.Call(typeof(MockSetupInfoStore).GetMethod("ReturnDefault").MakeGenericMethod(new[] { ele })); il.StoreIndirect(ele); } } else { il.LoadNull(); il.StoreIndirect(parameters[i].ParameterType); } } } il.Return(); return; } il.NewObject(typeof(NotImplementedException), Type.EmptyTypes); il.Throw(); il.Return(); return; }; _impl: { /*void*/ if (voidReturn) { if (found.MethodToCallType == MockSetup.MethodToCall.Exception || found.MethodToCallType == MockSetup.MethodToCall.Void) { } else { throw new ArgumentOutOfRangeException(method.Name, string.Format("the method {0}.{1} return type is void, but mock donot provide action callback;", this.TargetType.Name, method.Name)); } } else { /*返回结果类型不匹配*/ if (found.GetType() != typeof(MockSetup <,>).MakeGenericType(new[] { this.TargetType, method.ReturnType })) { goto _notImpl; } } /*返回基类类型,如果当前是接口类型的,则抛出异常*/ if (found.MethodIndex == 0) { if (@buildInterface) { goto _notImpl; } //this foreach (var m in this.GetMembers(sourceTypeOrInterfaceType)) { if (m.MemberType == MemberTypes.Method) { var pm = m as MethodInfo; var pp = pm.GetParameters(); if (pm.Name == found.Method.Name && pp.Length == found.Method.GetParameters().Length) { il.LoadArgument(0); for (ushort i = 1; i < pp.Length + 1; i++) { il.LoadArgument(i); } il.Call(pm); il.Return(); return; } } } throw new ArgumentOutOfRangeException(method.Name, string.Format("the method {0}.{1} cannot been found;", this.TargetType.Name, method.Name)); } /*用该值定位到执行的是哪个方法,因重载的原因,有15个方法以上,具体要看MockSetup<,>*/ var idx = MockSetupInfoStore.Enqueue(found); /*抛出异常*/ if (found.MethodIndex == -1) { il.LoadArgument(0); il.LoadConstant(idx); if (voidReturn) { il.Call(typeof(MockSetupInfoStore).GetMethod("Call_ExceptionWithNoResult").MakeGenericMethod(new[] { this.TargetType })); } else { il.Call(typeof(MockSetupInfoStore).GetMethod("Call_ExceptionWithResult").MakeGenericMethod(new[] { this.TargetType, method.ReturnType })); } il.Return(); return; } var callMethodName = typeof(MockSetupInfoStore).GetMethod(string.Concat("Call_", found.MethodIndex.ToString())); var makeGenericMethodParameterTypes = new List <Type>(found.MethodIndex); makeGenericMethodParameterTypes.Add(this.TargetType); if (found.MethodIndex >= 10 && found.MethodIndex <= 25) { /*没有参数的方法*/ if (found.MethodIndex == 10) { /*out 参数*/ for (var i = 0; i < parameters.Length; i++) { if (parameters[i].IsOut) { il.LoadArgument((ushort)(i + 1)); var ele = parameters[i].ParameterType.GetElementType(); if (ele.IsValueType) { if (this.IsEnumType(ele) || this.IsNullableEnumType(ele)) { il.Call(typeof(MockSetupInfoStore).GetMethod("ReturnDefault").MakeGenericMethod(new[] { ele })); il.StoreIndirect(Enum.GetUnderlyingType(ele)); } else { il.Call(typeof(MockSetupInfoStore).GetMethod("ReturnDefault").MakeGenericMethod(new[] { ele })); il.StoreIndirect(ele); } } else { il.LoadNull(); il.StoreIndirect(parameters[i].ParameterType); } } } makeGenericMethodParameterTypes.Add(method.ReturnType); il.LoadArgument(0); il.LoadConstant(idx); il.Call(callMethodName.MakeGenericMethod(makeGenericMethodParameterTypes.ToArray())); il.Return(); return; } if (found.CallbackMethodParameters == null || found.CallbackMethodParameters.Length == 0) { throw new ArgumentOutOfRangeException(method.Name, string.Format("{0}.{1} method need {2} parameters,but mock provider 0 parameters", this.TargetType.Name, method.Name, parameterTypes.Count)); } if (parameterTypes.Count != found.CallbackMethodParameters.Length) { throw new ArgumentException(string.Format("{0}.{1} method need {2} parameters,but the mock provide {3} parameters", this.TargetType.Name, method.Name, parameters.Length.ToString(), found.CallbackMethodParameters.Length.ToString()), method.Name); } for (var i = 1; i < found.CallbackMethodParameters.Length; i++) { if (parameterTypes[i] != found.CallbackMethodParameters[i].ParameterType) { throw new ArgumentException(string.Format("{0}.{1} method the {2} parameter type is {3},but the mock provide {4} type", this.TargetType.Name, method.Name, i.ToString(), parameterTypes[i].Name, found.CallbackMethodParameters[i].ParameterType.Name), method.Name); } makeGenericMethodParameterTypes.Add(found.CallbackMethodParameters[i].ParameterType); } makeGenericMethodParameterTypes.Add(method.ReturnType); /*out 参数*/ for (var i = 0; i < parameters.Length; i++) { if (parameters[i].IsOut) { il.LoadArgument((ushort)(i + 1)); var ele = parameters[i].ParameterType.GetElementType(); if (ele.IsValueType) { if (this.IsEnumType(ele) || this.IsNullableEnumType(ele)) { il.Call(typeof(MockSetupInfoStore).GetMethod("ReturnDefault").MakeGenericMethod(new[] { ele })); il.StoreIndirect(Enum.GetUnderlyingType(ele)); } else { il.Call(typeof(MockSetupInfoStore).GetMethod("ReturnDefault").MakeGenericMethod(new[] { ele })); il.StoreIndirect(ele); } } else { il.LoadNull(); il.StoreIndirect(parameters[i].ParameterType); } } } il.LoadArgument(0); il.LoadConstant(idx); for (ushort i = 1; i < makeGenericMethodParameterTypes.Count - 1; i++) { il.LoadArgument(i); } il.Call(callMethodName.MakeGenericMethod(makeGenericMethodParameterTypes.ToArray())); il.Return(); return; } if (found.MethodIndex >= 30 && found.MethodIndex <= 45) { /*没有参数的方法*/ if (found.MethodIndex == 30) { /*out 参数*/ for (var i = 0; i < parameters.Length; i++) { if (parameters[i].IsOut) { il.LoadArgument((ushort)(i + 1)); var ele = parameters[i].ParameterType.GetElementType(); if (ele.IsValueType) { if (this.IsEnumType(ele) || this.IsNullableEnumType(ele)) { il.Call(typeof(MockSetupInfoStore).GetMethod("ReturnDefault").MakeGenericMethod(new[] { ele })); il.StoreIndirect(Enum.GetUnderlyingType(ele)); } else { il.Call(typeof(MockSetupInfoStore).GetMethod("ReturnDefault").MakeGenericMethod(new[] { ele })); il.StoreIndirect(ele); } } else { il.LoadNull(); il.StoreIndirect(parameters[i].ParameterType); } } } il.LoadArgument(0); il.LoadConstant(idx); il.Call(callMethodName.MakeGenericMethod(makeGenericMethodParameterTypes.ToArray())); il.Return(); return; } if (parameterTypes.Count != found.CallbackMethodParameters.Length) { throw new ArgumentException(string.Format("{0}.{1} method need {2} parameters,but the mock provide {3} parameters", this.TargetType.Name, method.Name, parameters.Length.ToString(), found.CallbackMethodParameters.Length.ToString()), method.Name); } for (var i = 1; i < found.CallbackMethodParameters.Length; i++) { if (parameterTypes[i] != found.CallbackMethodParameters[i].ParameterType) { throw new ArgumentException(string.Format("{0}.{1} method the {2} parameter type is {3},but the mock provide {4} type", this.TargetType.Name, method.Name, i.ToString(), parameterTypes[i].Name, found.CallbackMethodParameters[i].ParameterType.Name), method.Name); } makeGenericMethodParameterTypes.Add(found.CallbackMethodParameters[i].ParameterType); } /*out 参数*/ for (var i = 0; i < parameters.Length; i++) { if (parameters[i].IsOut) { il.LoadArgument((ushort)(i + 1)); var ele = parameters[i].ParameterType.GetElementType(); if (ele.IsValueType) { if (this.IsEnumType(ele) || this.IsNullableEnumType(ele)) { il.Call(typeof(MockSetupInfoStore).GetMethod("ReturnDefault").MakeGenericMethod(new[] { ele })); il.StoreIndirect(Enum.GetUnderlyingType(ele)); } else { il.Call(typeof(MockSetupInfoStore).GetMethod("ReturnDefault").MakeGenericMethod(new[] { ele })); il.StoreIndirect(ele); } } else { il.LoadNull(); il.StoreIndirect(parameters[i].ParameterType); } } } il.LoadArgument(0); il.LoadConstant(idx); for (ushort i = 1; i < makeGenericMethodParameterTypes.Count; i++) { il.LoadArgument(i); } il.Call(callMethodName.MakeGenericMethod(makeGenericMethodParameterTypes.ToArray())); il.Return(); return; } }; }
/// <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); } }