/// <summary> /// Modifies the default constructor to initialize the "__initializedServices" field so that it can ensure that all /// services called with the <see cref="IInitialize.Initialize"/> are initialized once per object lifetime. /// </summary> /// <param name="containerType">The container type.</param> /// <param name="module">The module.</param> /// <param name="fieldEmitter">The field builder.</param> private void AddInitializationMap(TypeDefinition containerType, ModuleDefinition module, FieldBuilder fieldEmitter) { var initializationMapType = module.Import(typeof(Dictionary<int, int>)); var initializationMapField = new FieldDefinition("__initializedServices", FieldAttributes.Private | FieldAttributes.InitOnly, initializationMapType); containerType.Fields.Add(initializationMapField); var defaultConstructor = containerType.GetDefaultConstructor(); var body = defaultConstructor.Body; // __initializedServices = new Dictionary<int, int>(); var il = body.GetILProcessor(); var dictionaryCtor = module.ImportConstructor<Dictionary<int, int>>(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Newobj, dictionaryCtor); il.Emit(OpCodes.Stfld, initializationMapField); }
/// <summary> /// Defines the nested constructors for the singleton type. /// </summary> /// <param name="module">The target module.</param> /// <param name="nestedType">The nested type.</param> /// <returns>The static singleton constructor.</returns> private static MethodDefinition DefineNestedConstructors(ModuleDefinition module, TypeDefinition nestedType) { // Define the constructor for the nested t ype nestedType.AddDefaultConstructor(); var defaultConstructor = nestedType.GetDefaultConstructor(); defaultConstructor.IsPublic = true; var cctor = DefineStaticConstructor(module, nestedType); cctor.IsPublic = true; return cctor; }
/// <summary> /// Modifies the default constructor of a container type so that the jump labels used in the <see cref="IMicroContainer.GetInstance"/> implementation /// will be precalculated every time the compiled container is instantiated. /// </summary> /// <param name="module">The target module.</param> /// <param name="jumpTargetField">The field that holds the jump entries.</param> /// <param name="targetType">The container type.</param> /// <param name="getServiceHash">The hash calculation method.</param> /// <param name="serviceMap">The collection that contains the current list of dependencies and their respective implementations.</param> /// <param name="jumpTargets">A dictionary that maps dependencies to their respective label indexes.</param> private static void AddJumpEntries(ModuleDefinition module, FieldDefinition jumpTargetField, TypeDefinition targetType, MethodReference getServiceHash, IDictionary<IDependency, IImplementation> serviceMap, IDictionary<IDependency, int> jumpTargets) { var defaultContainerConstructor = targetType.GetDefaultConstructor(); var body = defaultContainerConstructor.Body; var il = body.GetILProcessor(); // Remove the last instruction and replace it with the jump entry // initialization instructions RemoveLastInstruction(body); // Initialize the jump targets in the default container constructor var getTypeFromHandleMethod = typeof(System.Type).GetMethod("GetTypeFromHandle", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); var getTypeFromHandle = module.Import(getTypeFromHandleMethod); // __jumpTargets = new Dictionary<int, int>(); var dictionaryCtor = module.ImportConstructor<Dictionary<int, int>>(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Newobj, dictionaryCtor); il.Emit(OpCodes.Stfld, jumpTargetField); var addMethod = module.ImportMethod<Dictionary<int, int>>("Add"); var index = 0; foreach (var dependency in serviceMap.Keys) { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, jumpTargetField); var serviceType = dependency.ServiceType; var serviceTypeRef = module.Import(serviceType); // Push the service type il.Emit(OpCodes.Ldtoken, serviceTypeRef); il.Emit(OpCodes.Call, getTypeFromHandle); // Push the service name var pushName = dependency.ServiceName == null ? il.Create(OpCodes.Ldnull) : il.Create(OpCodes.Ldstr, dependency.ServiceName); il.Append(pushName); // Calculate the hash code using the service type and service name il.Emit(OpCodes.Call, getServiceHash); // Map the current dependency to the index // that will be used in the GetInstance switch statement jumpTargets[dependency] = index; il.Emit(OpCodes.Ldc_I4, index++); il.Emit(OpCodes.Callvirt, addMethod); } }