Esempio n. 1
0
        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;
        }
Esempio n. 2
0
        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);
        }
Esempio n. 3
0
        /// <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);
        }
Esempio n. 4
0
        /// <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;
        }
Esempio n. 5
0
        /// <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;
        }
Esempio n. 6
0
        /// <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);
        }
Esempio n. 7
0
        /// <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);
        }
Esempio n. 8
0
        /// <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);
        }