/// <summary> /// Emits the instructions that will instantiate the current implementation. /// </summary> /// <param name="dependency">The dependency that describes the service to be instantiated.</param> /// <param name="serviceMap">The service map that contains the list of dependencies in the application.</param> /// <param name="targetMethod">The target method.</param> public void Emit(IDependency dependency, IDictionary <IDependency, IImplementation> serviceMap, MethodDefinition targetMethod) { var declaringType = targetMethod.DeclaringType; var module = declaringType.Module; var body = targetMethod.Body; var il = body.GetILProcessor(); // Emit the target implementation _implementation.Emit(dependency, serviceMap, targetMethod); // Determine the properties that need injection Func <PropertyInfo, bool> propertyFilter = p => _propertyFilter(p) && _propertyDependencyResolver(p) != null && p.CanWrite; var targetProperties = TargetType.GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (var property in targetProperties) { if (!propertyFilter(property)) { continue; } var curentDependency = _propertyDependencyResolver(property); if (!serviceMap.ContainsKey(curentDependency)) { continue; } EmitPropertySetter(serviceMap, targetMethod, module, il, property, curentDependency); } }
/// <summary> /// Emits the instructions that will instantiate the cached service implementation. /// </summary> /// <param name="dependency">The dependency that describes the service to be instantiated.</param> /// <param name="serviceMap">The service map that contains the list of dependencies in the application.</param> /// <param name="targetMethod">The target method.</param> public void Emit(IDependency dependency, IDictionary <IDependency, IImplementation> serviceMap, MethodDefinition targetMethod) { var declaringType = targetMethod.DeclaringType; var module = declaringType.Module; // Use the ICache instance that resides within the current container var cacheType = module.ImportType <ICache>(); var methodBody = targetMethod.Body; var locals = methodBody.Variables; var cacheVariable = new VariableDefinition(cacheType); locals.Add(cacheVariable); var worker = methodBody.GetILProcessor(); // var cache = (ICache)container.GetInstance(cacheType, string.Empty); var getCacheMethod = typeof(CacheRegistry).GetMethod("GetCache"); var getCacheInstanceMethod = module.Import(getCacheMethod); worker.Emit(OpCodes.Ldarg_0); worker.Emit(OpCodes.Call, getCacheInstanceMethod); worker.Emit(OpCodes.Stloc, cacheVariable); worker.Emit(OpCodes.Ldloc, cacheVariable); var createInstance = worker.Create(OpCodes.Nop); worker.Emit(OpCodes.Brfalse, createInstance); // if (cache != null) { var getItemMethod = module.ImportMethod <ICache>("get_Item"); var cacheKey = string.Format("Hiro Service Instance (ServiceName: {0}, ServiceType: {1}, Hash: {2})", dependency.ServiceName, dependency.ServiceType, dependency.GetHashCode()); // cachedResult = cache[cacheKey]; worker.Emit(OpCodes.Ldloc, cacheVariable); worker.Emit(OpCodes.Ldstr, cacheKey); worker.Emit(OpCodes.Callvirt, getItemMethod); worker.Emit(OpCodes.Brfalse, createInstance); // if (cachedResult != null) // return cachedResult; var endLabel = worker.Create(OpCodes.Nop); var objectType = module.ImportType(typeof(object)); var resultVariable = new VariableDefinition(objectType); methodBody.Variables.Add(resultVariable); worker.Emit(OpCodes.Ldloc, cacheVariable); worker.Emit(OpCodes.Ldstr, cacheKey); worker.Emit(OpCodes.Callvirt, getItemMethod); worker.Emit(OpCodes.Stloc, resultVariable); worker.Emit(OpCodes.Br, endLabel); worker.Append(createInstance); // Instantiate the actual service instance _actualImplementation.Emit(dependency, serviceMap, targetMethod); worker.Emit(OpCodes.Stloc, resultVariable); // Cache the results worker.Emit(OpCodes.Ldloc, cacheVariable); worker.Emit(OpCodes.Brfalse, endLabel); var setItemMethod = module.ImportMethod <ICache>("set_Item"); // cache[cacheKey] = result; worker.Emit(OpCodes.Ldloc, cacheVariable); worker.Emit(OpCodes.Ldstr, cacheKey); worker.Emit(OpCodes.Ldloc, resultVariable); worker.Emit(OpCodes.Callvirt, setItemMethod); worker.Append(endLabel); worker.Emit(OpCodes.Ldloc, resultVariable); }