示例#1
0
            public IxResolver(
                IxHost host,
                IIxInstance ownerInstance,
                [CanBeNull] IxResolveContext parentContext,
                [CanBeNull] IxResolveFrame parentFrame)
            {
                if (host == null)
                {
                    throw new ArgumentNullException(nameof(host));
                }

                if (ownerInstance == null)
                {
                    throw new ArgumentNullException(nameof(ownerInstance));
                }

                if (parentFrame != null)
                {
                    if (parentContext == null)
                    {
                        throw new ArgumentNullException();
                    }
                }

                Host          = host;
                OwnerInstance = ownerInstance;
                ParentFrame   = parentFrame;
                ParentContext = parentContext;
            }
示例#2
0
        private async ValueTask <IIxInstanceLock> Resolve(
            IIxInstance originInstance,
            IxIdentifier identifier,
            IxResolveContext context,
            [CanBeNull] IxResolveFrame frame)
        {
            if (originInstance == null)
            {
                throw new ArgumentNullException(nameof(originInstance));
            }

            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (originInstance.ProviderNode.Host != this)
            {
                throw new InvalidOperationException("You cannot use resolver from different host.");
            }

            ////if (context.IsFailed)
            ////{
            ////    throw new InvalidOperationException("You cannot do anything inside failed resolve context.");
            ////}
            return(await ResolveHandler.Delegate(originInstance, identifier, context, frame));
        }
示例#3
0
        /// <summary>
        /// Resolves list of <c>dependencies</c> from the specified origin. TODO: Implement <c>this</c> method with parallel
        /// resolution.
        /// </summary>
        /// <typeparam name="TResult">Target operation result type.</typeparam>
        /// <param name="originInstance">Origin instance. Where <c>dependencies</c> are queried.</param>
        /// <param name="dependencies">List of dependency identifiers.</param>
        /// <param name="context">Resolve <c>context</c>.</param>
        /// <param name="frame">The resolve sequence frame.</param>
        /// <param name="targetOperation">Operation that should be performed with resolved <c>dependencies</c>.</param>
        /// <returns>Result of target opration.</returns>
        public async ValueTask <TResult> ResolveList <TResult>(
            IIxInstance originInstance,
            HashSet <IxIdentifier> dependencies,
            IxResolveContext context,
            [CanBeNull] IxResolveFrame frame,
            Func <Dictionary <IxIdentifier, IIxInstance>, ValueTask <TResult> > targetOperation)
        {
            if (originInstance == null)
            {
                throw new ArgumentNullException(nameof(originInstance));
            }

            if (dependencies == null)
            {
                throw new ArgumentNullException(nameof(dependencies));
            }

            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (targetOperation == null)
            {
                throw new ArgumentNullException(nameof(targetOperation));
            }

            using (HashSet <IxIdentifier> .Enumerator enumerator = dependencies.GetEnumerator())
            {
                var result = new Dictionary <IxIdentifier, IIxInstance>();

                async ValueTask <TResult> ResolveItem()
                {
                    // ReSharper disable once AccessToDisposedClosure
                    if (!enumerator.MoveNext())
                    {
                        return(await targetOperation(result));
                    }

                    // ReSharper disable once AccessToDisposedClosure
                    IxIdentifier identifier = enumerator.Current;

                    using (IIxInstanceLock instanceLock = await Resolve(originInstance, identifier, context, frame))
                    {
                        result.Add(identifier, instanceLock.Target);
                        TResult resultItem = await ResolveItem();

                        if (identifier.Type == typeof(IIxResolver))
                        {
                            (instanceLock.Target as IxResolver)?.ClearParentResolveContext();
                        }

                        return(resultItem);
                    }
                }

                return(await ResolveItem());
            }
        }
示例#4
0
        private async ValueTask <IIxInstanceLock> RegistrationScopeBinder(
            IIxInstance originInstance,
            IxResolvePath resolvePath,
            IxResolveContext context,
            [CanBeNull] IxResolveFrame frame,
            IxResolveBoundDelegate resolveBound)
        {
            IIxInstance curInstance = originInstance;

            Critical.Assert(resolvePath.Path.Any(), "Registration scope binder does not support empty path.");

            lock (InstanceTreeSyncRoot)
            {
                while (curInstance != null)
                {
                    if (curInstance.ProviderNode == resolvePath.Root)
                    {
                        break;
                    }

                    curInstance = curInstance.ParentInstance;
                }
            }

            if (curInstance == null)
            {
                throw new InvalidOperationException("Resolve algorithms problems");
            }

            Func <IIxInstance, int, ValueTask <IIxInstanceLock> > resolvePathElements = null;

            resolvePathElements = async(parentInstance, index) =>
            {
                if (index < resolvePath.Path.Count - 1)
                {
                    using (IIxInstanceLock instanceLock = await Resolve(
                               parentInstance,
                               resolvePath.Path[index].Identifier,
                               context,
                               frame))
                    {
                        return(await resolvePathElements(instanceLock.Target, index + 1));
                    }
                }

                return(await resolveBound(parentInstance, resolvePath.Path.Last(), context));
            };

            IIxInstanceLock resultInstanceLock = await resolvePathElements(curInstance, 0);

            return(resultInstanceLock);
        }
示例#5
0
            public async ValueTask <IIxInstanceLock> Resolve(
                IxIdentifier identifier,
                IReadOnlyDictionary <IxIdentifier, object> arguments = null)
            {
                var context = new IxResolveContext(
                    OwnerInstance,
                    ParentContext,
                    arguments ?? new Dictionary <IxIdentifier, object>());

                using (new IxInstancePinLock(OwnerInstance))
                {
                    return(await Host.Resolve(OwnerInstance, identifier, context, ParentFrame));
                }
            }
            public IxResolveContext(
                IIxInstance originInstance,
                [CanBeNull] IxResolveContext parentContext,
                IReadOnlyDictionary <IxIdentifier, object> arguments)
            {
                Critical.CheckedAssert(originInstance != null, "Origin instance should be null.");
                Critical.CheckedAssert(arguments != null, "Arguments dictionary should not be null.");

                Arguments       = arguments;
                _originInstance = originInstance;
                ParentContext   = parentContext;
                _rootContext    = parentContext?._rootContext ?? this;

                Critical.CheckedAssert(_rootContext != null, "Root context should not be null.");
            }
示例#7
0
        /// <summary>
        /// Second initialization phase.
        /// </summary>
        /// <param name="config">Host configuration.</param>
        /// <returns>Async execution TPL task.</returns>
        public async Task Initialize(IIxHostConfig config)
        {
            var allConfigNodes = new HashSet <IIxProviderNodeConfig>();

            config.Nodes.Add(
                new IxStdProviderConfig
            {
                Identifier      = new IxIdentifier(typeof(IIxHost)),
                InstanceBuilder = new IxExistingInstanceFactoryConfig <IIxHost>(this),
                DisposeHandler  = obj => TaskEx.CompletedTask
            });

            Action <IIxProviderNodeConfig, IxProviderNode> buildNodeAction = null;

            buildNodeAction = (nodeConfig, parentNode) =>
            {
                if (!allConfigNodes.Add(nodeConfig))
                {
                    throw new InvalidOperationException(
                              "Configuration contains the same object multiple times. Currently it's not allowed to avoid visitor cycles.");
                }

                IxProviderNode node = ProviderNodeBuilder.Delegate(nodeConfig, parentNode);

                // parent node is null only for root scope.
                if (parentNode == null)
                {
                    _rootScope = (IxScope)node;
                }

                foreach (IIxProviderNodeConfig childConfig in nodeConfig.Nodes)
                {
                    buildNodeAction(childConfig, node);
                }
            };

            buildNodeAction(config, null);

            Action <IxProviderNode> importRegistrationsFromChildren = null;

            importRegistrationsFromChildren = node =>
            {
                foreach (IxProviderNode child in node.Nodes)
                {
                    importRegistrationsFromChildren(child);

                    // Applying export to parent filter
                    // while Blocking from exporting resolve pathes with zero-length.
                    foreach (KeyValuePair <IxIdentifier, IxResolvePath> kvp in
                             child.VisibleNodes.Where(
                                 x => child.ExportToParentFilter(x.Key) &&
                                 x.Value.Path.Any()))
                    {
                        if (node.VisibleNodes.ContainsKey(kvp.Key))
                        {
                            throw new InvalidOperationException("Export to parent node conflict.");
                        }

                        node.VisibleNodes.Add(kvp.Key, kvp.Value.ReRoot(node));
                    }
                }
            };

            importRegistrationsFromChildren(_rootScope);

            Action <IxProviderNode> exportRegistrationsToChildren = null;

            exportRegistrationsToChildren = node =>
            {
                KeyValuePair <IxIdentifier, IxResolvePath>[] registrationsToExport =
                    node.VisibleNodes.Where(x => node.ExportFilter(x.Key)).ToArray();

                if (!registrationsToExport.Any())
                {
                    return;
                }

                foreach (IxProviderNode child in node.Nodes)
                {
                    foreach (KeyValuePair <IxIdentifier, IxResolvePath> kvp in
                             registrationsToExport.Where(x => child.ImportFilter(x.Key)))
                    {
                        IxResolvePath resolvePath;
                        if (child.VisibleNodes.TryGetValue(kvp.Key, out resolvePath))
                        {
                            // Skipping self to children.
                            if (resolvePath.Path.Any())
                            {
                                // Direct cycle resolution replacement.
                                if (!resolvePath.Target.ParentReplacementNodes.ContainsKey(kvp.Key))
                                {
                                    resolvePath.Target.ParentReplacementNodes.Add(kvp.Key, kvp.Value);
                                }
                            }
                        }
                        else
                        {
                            child.VisibleNodes.Add(kvp.Key, kvp.Value);
                        }
                    }

                    exportRegistrationsToChildren(child);
                }
            };

            exportRegistrationsToChildren(_rootScope);

            _rootScopeInstance = _rootScope.GetRootInstance();
            var resolveContext = new IxResolveContext(_rootScopeInstance, null, new Dictionary <IxIdentifier, object>());

            using (IIxInstanceLock rootResolverLock = await Resolve(
                       _rootScopeInstance,
                       new IxIdentifier(typeof(IIxResolver)),
                       resolveContext,
                       null))
            {
                var resolver = (IxResolver)rootResolverLock.Target.Object;
                Critical.CheckedAssert(
                    resolver.ParentContext == null && resolver.ParentFrame == null,
                    "After resolve finished, resolver should not be bound to any context.");

                Resolver = resolver;
            }
        }
示例#8
0
 public void ClearParentResolveContext()
 {
     ParentFrame   = null;
     ParentContext = null;
 }