public CachingResult <Type> EndGeneration()
        {
            Assumes.IsTrue(this._isGenerationStarted);
            Assumes.IsFalse(this._isGenerationCompleted);
            CachingResult result = CachingResult.SucceededResult;

            result = result.MergeResult(this.GenerateGetCatalogMetadata());
            result = result.MergeResult(this.GenerateGetCatalogIndex());
            Type stubType = this._stubBuilder.CreateType();

            this._partsDefinitionBuilder.CreateType();
            this._exportsDefinitionBuilder.CreateType();
            this._importsDefinitionBuilder.CreateType();

            this._isGenerationCompleted = true;
            return(result.ToResult <Type>(stubType));
        }
        private CachingResult <MethodInfo> CachePartImportsOrExports <T>(IEnumerable <T> items, TypeBuilder definitionsTable, MethodBuilder stubFactoryMethod, Func <T, IDictionary <string, object> > cacheGenerator, string methodName)
        // in reality this is only ExportDefinition or ImportDefinition
        {
            Assumes.NotNull(items);
            Assumes.NotNull(definitionsTable);
            Assumes.NotNull(stubFactoryMethod);
            Assumes.NotNull(cacheGenerator);
            Assumes.NotNull(methodName);
            CachingResult result = CachingResult.SucceededResult;

            if (!items.Any())
            {
                return(result.ToResult <MethodInfo>(null));
            }

            Type itemType = null;

            if (typeof(T) == AssemblyCacheGenerator._importDefinitionType)
            {
                itemType = AssemblyCacheGenerator._importDefinitionType;
            }
            else
            {
                itemType = AssemblyCacheGenerator._exportDefinitionType;
            }

            //
            // internal static IEnumerable<T> CreateTs(ComposablePartDefinition owner)
            // {
            //    T[] items = new ImportDefinition[<count>];
            //
            //    IDictionary<string, object> dictionary0 = new Dictionary<string, object>();
            //    <populate the dictionary with the cache values>
            //    items[0] = CachingStubX.CreateTDefinition(dictinary0);
            //    ...
            //    IDictionary<string, object> dictionary<count-1> = new Dictionary<string, object>();
            //    <populate the dictionary with the cache values>
            //    items[<count-1>] = CachingStubX.CreateTDefinition(dictinary<count-1>);
            //    ...
            //    return items;
            // }

            // Generate the signature
            MethodBuilder itemsFactoryBuilder = definitionsTable.DefineMethod(
                methodName,
                MethodAttributes.Static | MethodAttributes.Assembly,
                typeof(IEnumerable <T>),
                new Type[] { AssemblyCacheGenerator._composablePartDefinitionType });
            ILGenerator ilGenerator = itemsFactoryBuilder.GetILGenerator();

            //
            // Generate array creation
            //
            this._generationServices.LoadValue(ilGenerator, items.Count());
            ilGenerator.Emit(OpCodes.Newarr, itemType);
            // At this point the array is on the stack

            int index = 0;

            foreach (T item in items)
            {
                // get the cache
                IDictionary <string, object> cache = cacheGenerator(item);

                //
                //items[<index>] = stub.CreateTDefinition(<dictionary>)
                //
                ilGenerator.Emit(OpCodes.Dup); // this will load the array on the stack
                result = result.MergeResult(this._generationServices.LoadValue(ilGenerator, index));

                ilGenerator.Emit(OpCodes.Ldarg_0);                                                   // load the part definition
                result = result.MergeResult(this._generationServices.LoadValue(ilGenerator, cache)); // load the dictionary
                ilGenerator.EmitCall(OpCodes.Call, stubFactoryMethod, null);

                ilGenerator.Emit(OpCodes.Stelem, itemType);
                index++;
                // at this point the duplicate array has been popped from the stack
            }

            // just return - the stack already contains the array
            ilGenerator.Emit(OpCodes.Ret);

            return(result.ToResult <MethodInfo>(itemsFactoryBuilder));
        }
        public CachingResult <MethodInfo> CachePartDefinition(ComposablePartDefinition partDefinition)
        {
            Assumes.NotNull(partDefinition);
            CachingResult result     = CachingResult.SucceededResult;
            string        methodName = string.Format(CultureInfo.InvariantCulture, "{0}", this._partsCounter);


            //Ftypeof
            // public static ComposablePartDefinition<>()
            // {
            //    // load dictionary
            //    return CachingStubX.CreatePartDefinition(<dictinary>, <importsFactory>, <exportsFactory>);
            // }

            // Generate the signature
            MethodBuilder partFactoryBuilder = this._partsDefinitionBuilder.DefineMethod(
                methodName,
                MethodAttributes.Static | MethodAttributes.Public,
                AssemblyCacheGenerator._composablePartDefinitionType,
                Type.EmptyTypes);
            ILGenerator ilGenerator = partFactoryBuilder.GetILGenerator();

            // Generate imports caching
            CachingResult <MethodInfo> importsFactoryResult = this.CachePartImportsOrExports <ImportDefinition>(
                partDefinition.ImportDefinitions,
                this._importsDefinitionBuilder,
                this._createImportDefinitionMethod,
                (import) => this._cachedCatalogSite.CacheImportDefinition(partDefinition, import),
                methodName);

            result = result.MergeErrors(importsFactoryResult.Errors);

            // Generate exports caching
            CachingResult <MethodInfo> exportsFactoryResult = this.CachePartImportsOrExports <ExportDefinition>(
                partDefinition.ExportDefinitions,
                this._exportsDefinitionBuilder,
                this._createExportDefinitionMethod,
                (export) => this._cachedCatalogSite.CacheExportDefinition(partDefinition, export),
                methodName);

            result = result.MergeErrors(exportsFactoryResult.Errors);


            // get the actual cache for the part definition
            IDictionary <string, object> cache = this._cachedCatalogSite.CachePartDefinition(partDefinition);

            //
            // now write the method
            //

            // load the cache dictionary on stack
            result = result.MergeResult(this._generationServices.LoadValue(ilGenerator, cache));

            // load the imports function pointer on stack
            MethodInfo importsFactory = importsFactoryResult.Value;

            if (importsFactory != null)
            {
                ilGenerator.Emit(OpCodes.Ldftn, importsFactory);
            }
            else
            {
                // load IntPtr.Zero
                ilGenerator.Emit(OpCodes.Ldsfld, AssemblyCacheGenerator._IntPtr_Zero);
            }

            // load the exports function pointer on stack
            MethodInfo exportsFactory = exportsFactoryResult.Value;

            if (exportsFactory != null)
            {
                ilGenerator.Emit(OpCodes.Ldftn, exportsFactory);
            }
            else
            {
                // load IntPtr.Zero
                ilGenerator.Emit(OpCodes.Ldsfld, AssemblyCacheGenerator._IntPtr_Zero);
            }

            // and then call into stub.CreatePartDefinition and return
            ilGenerator.EmitCall(OpCodes.Call, this._createPartDefinitionMethod, null);
            ilGenerator.Emit(OpCodes.Ret);
            this._partsCounter++;

            this.UpdateCatalogIndex(partDefinition, partFactoryBuilder);

            return(result.ToResult <MethodInfo>(partFactoryBuilder));
        }