public int CompareTo(IDependency other) { var areEqual = (other.Name == this.Name && other.DependencyType == this.DependencyType); if (areEqual) return 0; var otherHash = other.GetHashCode(); var thisHash = this.GetHashCode(); var isGreater = otherHash > thisHash; return isGreater ? 1 : -1; }
public int CompareTo(IDependency other) { var areEqual = (other.Name == this.Name && other.DependencyType == this.DependencyType); if (areEqual) { return(0); } var otherHash = other.GetHashCode(); var thisHash = this.GetHashCode(); var isGreater = otherHash > thisHash; return(isGreater ? 1 : -1); }
/// <summary> /// Defines the nested type that will instantiate the actual singleton service instance. /// </summary> /// <param name="module">The module that will host the singleton type.</param> /// <param name="singletonType">The singleton type.</param> /// <param name="instanceField">The field that will hold the singleton instance.</param> /// <param name="serviceMap">The service map that contains the list of dependencies in the application.</param> /// <param name="implementation">The implementation that will instantiate the dependency.</param> /// <param name="dependency">The dependency that will be instantiated by the singleton.</param> /// <param name="targetMethod">The method that will be used to instantiate the actual service instance.</param> private void DefineNestedType(ModuleDefinition module, TypeDefinition singletonType, FieldDefinition instanceField, IDictionary <IDependency, IImplementation> serviceMap, IImplementation implementation, IDependency dependency, MethodDefinition targetMethod) { var objectType = module.ImportType(typeof(object)); var nestedName = string.Format("Nested-{0}", dependency.GetHashCode()); const TypeAttributes nestedAttributes = TypeAttributes.NestedFamORAssem | TypeAttributes.Sealed | TypeAttributes.AutoClass | TypeAttributes.Class | TypeAttributes.AnsiClass; var nestedType = module.DefineClass(nestedName, "Hiro.Containers.Internal", nestedAttributes, objectType); singletonType.NestedTypes.Add(nestedType); nestedType.Fields.Add(instanceField); // Emit the static constructor body var cctor = DefineNestedConstructors(module, nestedType); EmitSingletonInstantiation(dependency, implementation, serviceMap, instanceField, cctor, module, targetMethod); }
/// <summary> /// Emits a service as a singleton type. /// </summary> /// <param name="targetMethod">The <see cref="IMicroContainer.GetInstance"/> method implementation.</param> /// <param name="dependency">The dependency that will be instantiated by the container.</param> /// <param name="implementation">The implementation that will be used to instantiate the dependency.</param> /// <param name="serviceMap">The service map the contains the current application dependencies.</param> public void EmitService(MethodDefinition targetMethod, IDependency dependency, IImplementation implementation, IDictionary <IDependency, IImplementation> serviceMap) { MethodDefinition getInstanceMethod = null; var worker = targetMethod.GetILGenerator(); // Emit only one singleton per dependency and call // the singleton GetInstance() method on every subsequent emit call if (_entries.ContainsKey(dependency)) { getInstanceMethod = _entries[dependency]; worker.Emit(OpCodes.Call, getInstanceMethod); return; } var declaringType = targetMethod.DeclaringType; var module = declaringType.Module; var serviceType = dependency.ServiceType; var typeName = serviceType.Name; var singletonName = string.Format("{0}ServiceSingleton-{1}", typeName, dependency.GetHashCode()); const TypeAttributes typeAttributes = TypeAttributes.NotPublic | TypeAttributes.AutoClass | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit; var objectType = module.Import(typeof(object)); var singletonType = AddDefaultSingletonConstructor(module, singletonName, typeAttributes, objectType); var instanceField = new FieldDefinition("__instance", FieldAttributes.Assembly | FieldAttributes.InitOnly | FieldAttributes.Static, objectType); DefineNestedType(module, singletonType, instanceField, serviceMap, implementation, dependency, targetMethod); getInstanceMethod = DefineGetInstance(singletonType, worker, instanceField); worker.Emit(OpCodes.Call, getInstanceMethod); var serviceTypeRef = module.Import(serviceType); worker.Emit(OpCodes.Unbox_Any, serviceTypeRef); // Cache the singleton method _entries[dependency] = getInstanceMethod; }
/// <summary> /// Emits a service as a singleton type. /// </summary> /// <param name="targetMethod">The <see cref="IMicroContainer.GetInstance"/> method implementation.</param> /// <param name="dependency">The dependency that will be instantiated by the container.</param> /// <param name="implementation">The implementation that will be used to instantiate the dependency.</param> /// <param name="serviceMap">The service map the contains the current application dependencies.</param> public void EmitService(MethodDefinition targetMethod, IDependency dependency, IImplementation implementation, IDictionary<IDependency, IImplementation> serviceMap) { MethodDefinition getInstanceMethod = null; var worker = targetMethod.GetILGenerator(); // Emit only one singleton per dependency and call // the singleton GetInstance() method on every subsequent emit call if (_entries.ContainsKey(dependency)) { getInstanceMethod = _entries[dependency]; worker.Emit(OpCodes.Call, getInstanceMethod); return; } var declaringType = targetMethod.DeclaringType; var module = declaringType.Module; var serviceType = dependency.ServiceType; var typeName = serviceType.Name; var singletonName = string.Format("{0}ServiceSingleton-{1}", typeName, dependency.GetHashCode()); const TypeAttributes typeAttributes = TypeAttributes.NotPublic | TypeAttributes.AutoClass | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit; var objectType = module.Import(typeof(object)); var singletonType = AddDefaultSingletonConstructor(module, singletonName, typeAttributes, objectType); var instanceField = new FieldDefinition("__instance", FieldAttributes.Assembly | FieldAttributes.InitOnly | FieldAttributes.Static, objectType); DefineNestedType(module, singletonType, instanceField, serviceMap, implementation, dependency, targetMethod); getInstanceMethod = DefineGetInstance(singletonType, worker, instanceField); worker.Emit(OpCodes.Call, getInstanceMethod); var serviceTypeRef = module.Import(serviceType); worker.Emit(OpCodes.Unbox_Any, serviceTypeRef); // Cache the singleton method _entries[dependency] = getInstanceMethod; }
/// <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); }
/// <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(); // Convert the token into a System.RuntimeType var getTypeFromHandle = module.ImportMethod<Type>("GetTypeFromHandle"); // 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); }
/// <summary> /// Defines the nested type that will instantiate the actual singleton service instance. /// </summary> /// <param name="module">The module that will host the singleton type.</param> /// <param name="singletonType">The singleton type.</param> /// <param name="instanceField">The field that will hold the singleton instance.</param> /// <param name="serviceMap">The service map that contains the list of dependencies in the application.</param> /// <param name="implementation">The implementation that will instantiate the dependency.</param> /// <param name="dependency">The dependency that will be instantiated by the singleton.</param> /// <param name="targetMethod">The method that will be used to instantiate the actual service instance.</param> private void DefineNestedType(ModuleDefinition module, TypeDefinition singletonType, FieldDefinition instanceField, IDictionary<IDependency, IImplementation> serviceMap, IImplementation implementation, IDependency dependency, MethodDefinition targetMethod) { var objectType = module.ImportType(typeof (object)); var nestedName = string.Format("Nested-{0}", dependency.GetHashCode()); const TypeAttributes nestedAttributes = TypeAttributes.NestedFamORAssem | TypeAttributes.Sealed | TypeAttributes.AutoClass | TypeAttributes.Class | TypeAttributes.AnsiClass; var nestedType = module.DefineClass(nestedName, "Hiro.Containers.Internal", nestedAttributes, objectType); singletonType.NestedTypes.Add(nestedType); nestedType.Fields.Add(instanceField); // Emit the static constructor body var cctor = DefineNestedConstructors(module, nestedType); EmitSingletonInstantiation(dependency, implementation, serviceMap, instanceField, cctor, module, targetMethod); }