void GenerateInnerInjectorType(TypeDefinition typeDef, InjectTypeInfo injectTypeInfo) { var injectorTypeDef = new TypeDefinition( "", "__GeneratedInjector", TypeAttributes.NestedPrivate | TypeAttributes.Sealed, module.TypeSystem.Object); var injectorImpl = new InterfaceImplementation(InjectorTypeRef); injectorTypeDef.Interfaces.Add(injectorImpl); GenerateDefaultConstructor(injectorTypeDef); GenerateInjectMethod(typeDef, injectorTypeDef, injectTypeInfo); GenerateCreateInstanceMethod(typeDef, injectorTypeDef, injectTypeInfo); GenerateInjectorGetterMethod(typeDef, injectorTypeDef); typeDef.NestedTypes.Add(injectorTypeDef); }
void GenerateInjectMethod(TypeDefinition typeDef, TypeDefinition injectorTypeDef, InjectTypeInfo injectTypeInfo) { var methodDef = new MethodDefinition("Inject", MethodAttributes.Public | MethodAttributes.Virtual, module.TypeSystem.Void); injectorTypeDef.Methods.Add(methodDef); methodDef.Parameters.Add(new ParameterDefinition(module.TypeSystem.Object) { Name = "instance" }); methodDef.Parameters.Add(new ParameterDefinition(ObjectResolverTypeRef) { Name = "resolver" }); methodDef.Parameters.Add(new ParameterDefinition(InjectParameterListTypeRef) { Name = "parameters" }); var body = methodDef.Body; var processor = body.GetILProcessor(); processor.Emit(OpCodes.Nop); var instanceVariableDef = new VariableDefinition(typeDef); body.Variables.Add(instanceVariableDef); if (injectTypeInfo.InjectMethods != null || injectTypeInfo.InjectFields != null || injectTypeInfo.InjectProperties != null) { processor.Emit(OpCodes.Ldarg_1); processor.Emit(OpCodes.Unbox_Any, typeDef); processor.Emit(OpCodes.Stloc_S, instanceVariableDef); } if (injectTypeInfo.InjectFields != null) { foreach (var injectField in injectTypeInfo.InjectFields) { var fieldRef = module.ImportReference(injectField); var fieldTypeRef = Utils.CreateParameterTypeReference(module, injectField.FieldType, typeDef); processor.Emit(OpCodes.Ldloc_S, instanceVariableDef); // TODO: Add ExceptionHandler // instance.Field = resolver.Resolve(Type) processor.Emit(OpCodes.Ldarg_2); processor.Emit(OpCodes.Ldtoken, fieldTypeRef); processor.Emit(OpCodes.Call, GetTypeFromHandleRef); processor.Emit(OpCodes.Call, ResolveMethodRef); processor.Emit(OpCodes.Stfld, fieldRef); } } if (injectTypeInfo.InjectProperties != null) { foreach (var injectProperty in injectTypeInfo.InjectProperties) { var propertySetterRef = module.ImportReference(injectProperty.SetMethod); var propertyTypeRef = Utils.CreateParameterTypeReference(module, injectProperty.PropertyType, typeDef); processor.Emit(OpCodes.Ldloc_S, instanceVariableDef); // TODO: Add ExceptionHandler // instance.Property = resolver.Resolve(Type) processor.Emit(OpCodes.Ldarg_2); processor.Emit(OpCodes.Ldtoken, propertyTypeRef); processor.Emit(OpCodes.Call, GetTypeFromHandleRef); processor.Emit(OpCodes.Call, ResolveMethodRef); processor.Emit(OpCodes.Callvirt, propertySetterRef); } } if (injectTypeInfo.InjectMethods != null) { foreach (var injectMethod in injectTypeInfo.InjectMethods) { var injectMethodRef = module.ImportReference(injectMethod.MethodInfo); processor.Emit(OpCodes.Ldloc_S, instanceVariableDef); for (var i = 0; i < injectMethodRef.Parameters.Count; i++) { var paramDef = injectMethodRef.Parameters[i]; var paramInfo = injectMethod.ParameterInfos[i]; var paramTypeRef = Utils.CreateParameterTypeReference(module, paramInfo.ParameterType, typeDef); var paramVariableDef = new VariableDefinition(paramDef.ParameterType); body.Variables.Add(paramVariableDef); // TODO: Add ExceptionHandler processor.Emit(OpCodes.Ldarg_2); processor.Emit(OpCodes.Ldtoken, paramTypeRef); processor.Emit(OpCodes.Call, GetTypeFromHandleRef); processor.Emit(OpCodes.Ldstr, paramInfo.Name); processor.Emit(OpCodes.Ldarg_3); processor.Emit(OpCodes.Call, ResolveOrParameterMethodRef); processor.Emit(OpCodes.Unbox_Any, paramTypeRef); processor.Emit(OpCodes.Stloc_S, paramVariableDef); processor.Emit(OpCodes.Ldloc_S, paramVariableDef); } processor.Emit(OpCodes.Callvirt, injectMethodRef); } } processor.Emit(OpCodes.Ret); }
void GenerateCreateInstanceMethod( TypeDefinition typeDef, TypeDefinition injectorTypeDef, InjectTypeInfo injectTypeInfo) { var methodDef = new MethodDefinition("CreateInstance", MethodAttributes.Public | MethodAttributes.Virtual, module.TypeSystem.Object); var injectMethodDef = injectorTypeDef.Methods.Single(x => x.Name == "Inject"); injectorTypeDef.Methods.Add(methodDef); methodDef.Parameters.Add(new ParameterDefinition(ObjectResolverTypeRef) { Name = "resolver" }); methodDef.Parameters.Add(new ParameterDefinition(InjectParameterListTypeRef) { Name = "parameters" }); var body = methodDef.Body; var processor = body.GetILProcessor(); processor.Emit(OpCodes.Nop); if (injectTypeInfo.InjectConstructor == null || injectTypeInfo.Type.IsSubclassOf(typeof(UnityEngine.Component))) { processor.Emit(OpCodes.Ldnull); processor.Emit(OpCodes.Ret); return; } var resultVariableDef = new VariableDefinition(module.TypeSystem.Object); body.Variables.Add(resultVariableDef); var constructorRef = module.ImportReference(injectTypeInfo.InjectConstructor.ConstructorInfo); for (var i = 0; i < constructorRef.Parameters.Count; i++) { var paramDef = constructorRef.Parameters[i]; var paramInfo = injectTypeInfo.InjectConstructor.ParameterInfos[i]; var paramTypeRef = Utils.CreateParameterTypeReference(module, paramInfo.ParameterType, typeDef); var paramVariableDef = new VariableDefinition(paramTypeRef); body.Variables.Add(paramVariableDef); // TODO: Add ExceptionHandler // Call ResolveOrParameter(IObjectResolver, Type, string, IReadOnlyList<IInjectParameter>) processor.Emit(OpCodes.Ldarg_1); processor.Emit(OpCodes.Ldtoken, paramTypeRef); processor.Emit(OpCodes.Call, GetTypeFromHandleRef); processor.Emit(OpCodes.Ldstr, paramInfo.Name); processor.Emit(OpCodes.Ldarg_2); processor.Emit(OpCodes.Call, ResolveOrParameterMethodRef); processor.Emit(OpCodes.Unbox_Any, paramTypeRef); processor.Emit(OpCodes.Stloc_S, paramVariableDef); processor.Emit(OpCodes.Ldloc_S, paramVariableDef); } processor.Emit(OpCodes.Newobj, constructorRef); processor.Emit(OpCodes.Stloc_0); processor.Emit(OpCodes.Ldarg_0); processor.Emit(OpCodes.Ldloc_0); processor.Emit(OpCodes.Ldarg_1); processor.Emit(OpCodes.Ldarg_2); processor.Emit(OpCodes.Callvirt, injectMethodDef); processor.Emit(OpCodes.Ldloc_0); processor.Emit(OpCodes.Ret); }