public void SetupParameters(MethodBuilder methodBuilder, GenericParameterMapper parentMapper) { if (this._methodToOverride.IsGenericMethod) { Type[] genericArguments = this._methodToOverride.GetGenericArguments(); string[] names = (from t in genericArguments select t.Name).ToArray(); GenericTypeParameterBuilder[] builders = methodBuilder.DefineGenericParameters(names); for (int i = 0; i < genericArguments.Length; i++) { builders[i].SetGenericParameterAttributes(genericArguments[i].GenericParameterAttributes); Type[] source = (from ct in genericArguments[i].GetGenericParameterConstraints() select parentMapper.Map(ct)).ToArray(); Type[] interfaceConstraints = (from t in source where t.IsInterface select t).ToArray(); Type baseConstraint = (from t in source where !t.IsInterface select t).FirstOrDefault(); if (baseConstraint != (Type)null) { builders[i].SetBaseTypeConstraint(baseConstraint); } if (interfaceConstraints.Length != 0) { builders[i].SetInterfaceConstraints(interfaceConstraints); } } this._genericParameterMapper = new GenericParameterMapper(genericArguments, builders.Cast <Type>().ToArray(), parentMapper); } else { this._genericParameterMapper = parentMapper; } }
private void CreateTypeBuilder() { TypeAttributes newAttributes = _typeToIntercept.Attributes; newAttributes = FilterTypeAttributes(newAttributes); Type baseClass = GetGenericType(_typeToIntercept); ModuleBuilder moduleBuilder = GetModuleBuilder(); _typeBuilder = moduleBuilder.DefineType($"DynamicModule.Wrapped_{_typeToIntercept.Name}_{Guid.NewGuid().ToString("N")}", newAttributes, baseClass); _mainTypeMapper = DefineGenericArguments(_typeBuilder, baseClass); if (_typeToIntercept.IsGenericType) { Type definition = _typeToIntercept.GetGenericTypeDefinition(); Type[] mappedParameters = (from t in definition.GetGenericArguments() select _mainTypeMapper.Map(t)).ToArray(); _targetType = definition.MakeGenericType(mappedParameters); } else { _targetType = _typeToIntercept; } }
public GenericParameterMapper(Type type, GenericParameterMapper parent) { if (type == null) { throw new ArgumentNullException(nameof(type)); } if (type.IsGenericType) { if (type.IsGenericTypeDefinition) { throw new ArgumentException("Cannot Map Generic Type Definition"); } this._parent = parent; this._localMappings = GenericParameterMapper.CreateMappings(type.GetGenericTypeDefinition().GetGenericArguments(), type.GetGenericArguments()); } else { this._localMappings = GenericParameterMapper.EmptyMappings; this._parent = null; } }
public InterceptionAttributeAnalysis(TypeBuilder typeBuilder, Type typeToIntercept, GenericParameterMapper targetTypeParameterMapper) { _typeBuilder = typeBuilder; _typeToIntercept = typeToIntercept; _targetMethodInfos = GetMethodsToIntercept(); if (!HasInterceptionAttribute(_typeToIntercept)) { _targetMethodInfos = _targetMethodInfos.Where(methodInfo => HasInterceptionAttribute(methodInfo)); } var targetType = _typeToIntercept; if (_typeToIntercept.IsGenericType) { targetType = ((ModuleBuilder)_typeBuilder.Module).DefineType($"__Anonymous__GenericType__{_typeToIntercept.Name}", TypeAttributes.Public | TypeAttributes.BeforeFieldInit | TypeAttributes.Sealed).CreateType(); } var mapType = typeof(ProxyMap <>).MakeGenericType(targetType); _mapFieldInfo = mapType.GetField("Map", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); _proxyDelegates = (List <ProxyDelegate>)_mapFieldInfo.GetValue(null); _mapGetMethod = _mapFieldInfo.FieldType.GetMethod("get_Item", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, new Type[] { typeof(int) }, new ParameterModifier[0]); methodCount = _proxyDelegates.Count; _targetTypeParameterMapper = targetTypeParameterMapper; }
/*Derived Method process: * baseMethod.ReturnType DerivedMethod(baseMethod.Parameters) * { * IMethodInvocation input = Wrapped(baseMethod.Parameters); * var methodReturn = @delegate(input); * if(methodReturn.Exception==null) * return (baseMethod.ReturnType)methodReturn.ReturnValue; * throw methodReturn.Exception; * } */ private void AddMethod(MethodInfo methodInfo, InvokeHandlerDelegate @delegate) { var attr = methodInfo.Attributes & ~MethodAttributes.VtableLayoutMask & ~MethodAttributes.Abstract; var methodBuilder = _typeBuilder.DefineMethod(methodInfo.Name, attr); Type declaringType = methodInfo.DeclaringType; GenericParameterMapper mapper = (declaringType.IsGenericType && declaringType != methodInfo.ReflectedType) ? new GenericParameterMapper(declaringType, _targetTypeParameterMapper) : _targetTypeParameterMapper; MethodOverrideParameterMapper paraMapper = new MethodOverrideParameterMapper(methodInfo); paraMapper.SetupParameters(methodBuilder, mapper); methodBuilder.SetReturnType(paraMapper.GetReturnType()); methodBuilder.SetParameters(methodInfo.GetParameters().Select(pi => paraMapper.GetParameterType(pi.ParameterType)).ToArray()); var il = methodBuilder.GetILGenerator(); il.DeclareLocal(typeof(ProxyDelegate)); //local 0 il.DeclareLocal(typeof(MethodInvocation)); //local 1 il.DeclareLocal(typeof(IMethodReturn)); //local 2 //add ProxyDelegate to ProxyMap _proxyDelegates.Add(new ProxyDelegate { @delegate = @delegate, methodInfo = methodInfo }); var parameterInfos = methodInfo.GetParameters(); int parameterLength = parameterInfos.Length; int paramNum = 1; foreach (ParameterInfo pi2 in parameterInfos) { methodBuilder.DefineParameter(paramNum++, pi2.Attributes, pi2.Name); } //the ref parameter(ref or out) set a default value for (int i = 0; i < parameterLength; i++) { if (paraMapper.GetParameterType(parameterInfos[i].ParameterType).IsByRef) { EmitLoadArgument(il, i); il.Emit(OpCodes.Initobj, paraMapper.GetElementType(parameterInfos[i].ParameterType)); } } //ProxyDelegate proxyDelegate=ProxyMap<$Type>.Map[$methodCount]; il.Emit(OpCodes.Ldsfld, _mapFieldInfo); EmitLoadConstant(il, methodCount); il.Emit(OpCodes.Callvirt, _mapGetMethod); il.Emit(OpCodes.Stloc_0); //set the value to local 0 il.Emit(OpCodes.Ldarg_0); //load this il.Emit(OpCodes.Ldloc_0); //load local 0 il.Emit(OpCodes.Ldfld, typeof(ProxyDelegate).GetField("methodInfo")); //new object[] EmitLoadConstant(il, parameterLength); il.Emit(OpCodes.Newarr, typeof(object)); for (int i = 0; i < parameterLength; i++) { il.Emit(OpCodes.Dup);//copy the value to the top of the stack EmitLoadConstant(il, i); EmitLoadArgument(il, i); var parameterType = paraMapper.GetParameterType(parameterInfos[i].ParameterType); var isByRef = parameterType.IsByRef; if (isByRef) { parameterType = parameterType.GetElementType(); } if (parameterInfos[i].ParameterType.IsValueType || parameterInfos[i].ParameterType.IsGenericParameter) { il.Emit(OpCodes.Box, paraMapper.GetParameterType(parameterInfos[i].ParameterType)); } else if (isByRef) { il.Emit(OpCodes.Ldobj, parameterType); if (parameterType.IsValueType || parameterType.IsGenericParameter) { il.Emit(OpCodes.Box, parameterType); } } il.Emit(OpCodes.Stelem_Ref); } il.Emit(OpCodes.Newobj, typeof(MethodInvocation).GetConstructor(new Type[] { typeof(object), typeof(MethodBase), typeof(object[]) })); //call new MethodInvocation() il.Emit(OpCodes.Stloc_1); //set new obj to local 1 //IMethodReturn r=proxyDelegate.@delegate(input) il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ldfld, typeof(ProxyDelegate).GetField("delegate")); il.Emit(OpCodes.Ldloc_1); il.Emit(OpCodes.Callvirt, @delegate.GetType().GetMethod("Invoke")); il.Emit(OpCodes.Stloc_2); // if (r.Exception==null) il.Emit(OpCodes.Ldloc_2); il.Emit(OpCodes.Callvirt, typeof(IMethodReturn).GetMethod("get_Exception", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)); Label lbTrue = il.DefineLabel(); il.Emit(OpCodes.Brtrue_S, lbTrue); //false //handle ref or out parameters var getOutputs = typeof(IMethodReturn).GetMethod("get_Outputs", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); var getItem = typeof(IParameterCollection).GetMethod("get_Item", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(int) }, new ParameterModifier[0]); int refParamNums = 0; for (int i = 0; i < parameterLength; i++) { var parameterType = paraMapper.GetParameterType(parameterInfos[i].ParameterType); if (parameterType.IsByRef) { EmitLoadArgument(il, i); il.Emit(OpCodes.Ldloc_2); il.Emit(OpCodes.Callvirt, getOutputs); EmitLoadConstant(il, refParamNums++); il.Emit(OpCodes.Callvirt, getItem); var elementType = parameterType.GetElementType(); if (elementType.IsValueType || elementType.IsGenericParameter) { il.Emit(OpCodes.Unbox_Any, elementType); } else { il.Emit(OpCodes.Castclass, elementType); } il.Emit(OpCodes.Stobj, elementType); } } //return ($ReturnType)r.ReturnValue; var returnType = paraMapper.GetReturnType(); if (returnType != typeof(void)) { il.Emit(OpCodes.Ldloc_2); il.Emit(OpCodes.Callvirt, typeof(IMethodReturn).GetMethod("get_ReturnValue")); if (returnType.IsValueType || returnType.IsGenericParameter) { il.Emit(OpCodes.Unbox_Any, returnType); } else { il.Emit(OpCodes.Castclass, returnType); } } il.Emit(OpCodes.Ret); //ture //throw r.Exception il.MarkLabel(lbTrue); il.Emit(OpCodes.Ldloc_2); il.Emit(OpCodes.Callvirt, typeof(IMethodReturn).GetMethod("get_Exception", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)); il.Emit(OpCodes.Throw); //increase methodCount methodCount++; }
public GenericParameterMapper(Type[] reflectedParameters, Type[] generatedParameters, GenericParameterMapper parent) { this._parent = parent; this._localMappings = GenericParameterMapper.CreateMappings(reflectedParameters, generatedParameters); }