private TBase CreateInstance() { var typeBuilder = _moduleBuilder.DefineType(_typeName); typeBuilder.SetParent(typeof(TBase)); var implementationField = typeBuilder.DefineField("__implementation", typeof(IImplementation), FieldAttributes.Private); var baseConstructor = typeof(TBase).GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { }, null); // Constructor var method = typeBuilder.DefineMethod(".ctor", MethodAttributes.Public | MethodAttributes.HideBySig); method.SetReturnType(typeof(void)); method.SetParameters(typeof(IImplementation)); method.DefineParameter(1, ParameterAttributes.None, "implementation"); var constructorWriter = method.GetILGenerator(); // Writing body constructorWriter.Emit(OpCodes.Ldarg_0); constructorWriter.Emit(OpCodes.Call, baseConstructor); constructorWriter.Emit(OpCodes.Nop); constructorWriter.Emit(OpCodes.Nop); constructorWriter.Emit(OpCodes.Ldarg_0); constructorWriter.Emit(OpCodes.Ldarg_1); constructorWriter.Emit(OpCodes.Stfld, implementationField); constructorWriter.Emit(OpCodes.Nop); constructorWriter.Emit(OpCodes.Ret); _implementation = new RuntimeImplementation(); // Other methods foreach (var contributor in _contributors) { contributor.Contribute(typeBuilder, implementationField, _implementation); } var type = typeBuilder.CreateType(); return((TBase)Activator.CreateInstance(type, _implementation)); }
void ITypeContributor.Contribute(TypeBuilder typeBuilder, FieldBuilder implementationField, RuntimeImplementation delegatedImplementation) { // Define the method var methodBuilder = typeBuilder.DefineMethod(_name, _accessibility | MethodAttributes.HideBySig); methodBuilder.SetReturnType(_callback.Method.ReturnType); methodBuilder.SetParameters(_callback.Method.GetParameters().Select(x => x.ParameterType).ToArray()); // Define attributes foreach (var attribute in _attributes) { var types = attribute.Value.Select(x => x.GetType()).ToArray(); var attributeCtor = attribute.Key.GetConstructor(types); methodBuilder.SetCustomAttribute( new CustomAttributeBuilder(attributeCtor, attribute.Value) ); } // Define parameters var parameters = new List <ParameterBuilder>(); foreach (var param in _callback.Method.GetParameters()) { parameters.Add(methodBuilder.DefineParameter(param.Position + 1, ParameterAttributes.None, param.Name)); } // Prepare the implementation var bodyWriter = methodBuilder.GetILGenerator(); bodyWriter.Emit(OpCodes.Ldarg_0); bodyWriter.Emit(OpCodes.Ldfld, implementationField); bodyWriter.Emit(OpCodes.Ldstr, _name); // Build the array of objects var arguments = bodyWriter.DeclareLocal(typeof(object[])); bodyWriter.Emit(OpCodes.Ldc_I4, parameters.Count); bodyWriter.Emit(OpCodes.Newarr, typeof(object)); bodyWriter.Emit(OpCodes.Stloc, arguments); // Set the array foreach (var parameter in _callback.Method.GetParameters()) { bodyWriter.Emit(OpCodes.Ldloc, arguments); bodyWriter.Emit(OpCodes.Ldc_I4, parameter.Position); bodyWriter.Emit(OpCodes.Ldarg, parameter.Position + 1); if (parameter.ParameterType.IsValueType) { bodyWriter.Emit(OpCodes.Box, parameter.ParameterType); } bodyWriter.Emit(OpCodes.Stelem_Ref); } // Call Invoke and return the result bodyWriter.Emit(OpCodes.Ldloc, arguments); bodyWriter.EmitCall(OpCodes.Callvirt, typeof(IImplementation).GetMethod("Invoke"), new Type[0]); bodyWriter.Emit(OpCodes.Unbox_Any, _callback.Method.ReturnType); bodyWriter.Emit(OpCodes.Stloc_0); bodyWriter.Emit(OpCodes.Ldloc_0); bodyWriter.Emit(OpCodes.Ret); delegatedImplementation.RegisterCallback(_name, methodBuilder, args => { _wasCalled = true; try { return(_callback.DynamicInvoke(args)); } catch (TargetInvocationException ex) { throw ex.InnerException; } } ); }