예제 #1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="IxSingletonInstance"/> class.
        /// </summary>
        /// <param name="providerNode">Singleton provider.</param>
        /// <param name="parentInstance">Parent instance.</param>
        /// <param name="context">The resolve context.</param>
        /// <param name="frame">The resolution frame in the resolve sequence.</param>
        /// <param name="creatorTempLock">First temp lock for the creator of a new instance.</param>
        public IxSingletonInstance(
            IxSingletonProvider providerNode,
            IIxInstance parentInstance,
            IxHost.IxResolveContext context,
            [CanBeNull] IxResolveFrame frame,
            out IIxInstanceLock creatorTempLock)
            : base(providerNode, parentInstance, out creatorTempLock)
        {
            if (parentInstance == null)
            {
                throw new ArgumentNullException(nameof(parentInstance));
            }

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

            Debug.Assert(ProviderNode.InstanceFactory != null, "IxSingletonProvider always have instance factory.");

            var newFrame = new IxResolveFrame(frame, this);

            SetObjectCreationTask(
                ProviderNode.InstanceFactory.Factory(
                    this,
                    parentInstance,
                    context,
                    newFrame));
        }
예제 #2
0
        /// <inheritdoc/>
        public void RemoveLock(IIxInstanceLock instanceLock)
        {
            if (instanceLock == null)
            {
                throw new ArgumentNullException(nameof(instanceLock));
            }

            EnsureTreeLocked();

            if (ReferenceEquals(instanceLock, _initTempLock))
            {
                Critical.Assert(
                    _objectCreationTask != null,
                    "You need to setup instance object factory before releasing creator lock.");
                Critical.Assert(
                    _objectCreationTask.Value.IsCompleted,
                    "Creator lock should be removed only after object instantiation completes.");

                _initTempLock = null;
            }


            // --------- We are under tree lock --------------
            if (!_locks.Remove(instanceLock))
            {
                Critical.Assert(false, "Lock was not registered in the target or already removed.");
            }

            UpdateDisposeSuspendState();

            UpdateChildrenDisposeCompleteSuspendState();
        }
예제 #3
0
            void IIxInstance.RemoveLock(IIxInstanceLock instanceLock)
            {
                ////throw new NotSupportedException(
                ////    "This is completely virtual object and cannot be locked/unlocked.");

                // Do nothing.
            }
예제 #4
0
        private ResolveDelegate DirectCycleResolveInterceptor(ResolveDelegate next)
        {
            return(async(originInstance, identifier, context, frame) =>
            {
                // Direct cycle resolve case.
                if (originInstance.ProviderNode.Identifier == identifier)
                {
                    IxResolvePath resolvePath;

                    // Using parent replacement provider, if it exists.
                    if (originInstance.ProviderNode.ParentReplacementNodes.TryGetValue(identifier, out resolvePath))
                    {
                        return await resolvePath.Target.ScopeBinder(
                            originInstance,
                            resolvePath,
                            context,
                            frame,
                            async (parentInstance, provider, c) =>
                        {
                            // While we have temporary lock, we needs to put permanent lock.
                            IIxInstanceLock resolvedInstanceTempLock =
                                await provider.GetInstance(parentInstance, identifier, c, frame);

                            return resolvedInstanceTempLock;
                        });
                    }
                }

                return await next(originInstance, identifier, context, frame);
            });
        }
예제 #5
0
        private ResolveDelegate StdResolveInterceptor(ResolveDelegate next)
        {
            return(async(originInstance, identifier, context, frame) =>
            {
                IxResolvePath resolvePath;
                if (!originInstance.ProviderNode.VisibleNodes.TryGetValue(identifier, out resolvePath))
                {
                    return await next(originInstance, identifier, context, frame);
                }

                return await resolvePath.Target.ScopeBinder(
                    originInstance,
                    resolvePath,
                    context,
                    frame,
                    async (parentInstance, provider, c) =>
                {
                    // While we have temporary lock, we needs to put permanent lock.
                    IIxInstanceLock resolvedInstanceTempLock =
                        await provider.GetInstance(parentInstance, identifier, c, frame);

                    return resolvedInstanceTempLock;
                });
            });
        }
예제 #6
0
        public IxLock(IIxInstanceLock instanceLock)
        {
            Critical.Assert(instanceLock != null, "Lock target should not be null.");

            _instanceLock = instanceLock;
            _target       = (T)_instanceLock.Target.Object;
        }
예제 #7
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());
            }
        }
예제 #8
0
 /// <summary>
 /// Initializes a new instance of the <see cref="IxScopeInstance"/> class.
 /// </summary>
 /// <param name="providerNode">Owner provider.</param>
 /// <param name="parentInstance">Parent instance.</param>
 /// <param name="creatorTempLock">First temp lock for the creator of a new instance.</param>
 public IxScopeInstance(
     IxProviderNode providerNode,
     [CanBeNull] IIxInstance parentInstance,
     out IIxInstanceLock creatorTempLock)
     : base(providerNode, parentInstance, out creatorTempLock)
 {
     SetObjectCreationTask(new ValueTask <object>(providerNode));
 }
예제 #9
0
        /// <inheritdoc/>
        public override async ValueTask <IIxInstanceLock> GetInstance(
            IIxInstance parentInstance,
            IxIdentifier identifier,
            IxHost.IxResolveContext context,
            [CanBeNull] IxResolveFrame frame)
        {
            if (parentInstance == null)
            {
                throw new ArgumentNullException(nameof(parentInstance));
            }

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

            IIxInstanceLock     creatorLock = null;
            IxSingletonInstance instance;

            // Re-implement this with more advanced Half-Instantiation with loop detection.
            lock (Host.InstanceTreeSyncRoot)
            {
                instance = parentInstance.GetData(this) as IxSingletonInstance;
                if (instance == null)
                {
                    // TODO: Detect cycles.
                    Debug.Assert(InstanceFactory != null, "InstanceFactory != null");

                    instance = new IxSingletonInstance(this, parentInstance, context, frame, out creatorLock);

                    parentInstance.SetData(this, instance);
                }
            }

            try
            {
                await instance.ObjectCreationTask;
                return(creatorLock ?? new IxInstancePinLock(instance));
            }
            catch
            {
                if (creatorLock != null)
                {
                    lock (Host.InstanceTreeSyncRoot)
                    {
                        parentInstance.SetData(this, null);
                    }

                    creatorLock.Dispose();
                }

                throw;
            }
        }
예제 #10
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);
        }
예제 #11
0
        /// <inheritdoc/>
        public void AddOwnedLock(IIxInstanceLock instanceLock)
        {
            if (instanceLock == null)
            {
                throw new ArgumentNullException(nameof(instanceLock));
            }

            EnsureTreeLocked();
            if (!_ownedLocks.Add(instanceLock))
            {
                Critical.Assert(false, "Owned Lock already registered in the owner.");
            }
        }
예제 #12
0
        /// <inheritdoc/>
        public void RemoveOwnedLock(IIxInstanceLock instanceLock)
        {
            if (instanceLock == null)
            {
                throw new ArgumentNullException(nameof(instanceLock));
            }

            EnsureTreeLocked();

            // --------- We are under tree lock --------------
            if (!_ownedLocks.Remove(instanceLock))
            {
                Critical.Assert(false, "Owned lock was not registered in the owner or already removed.");
            }
        }
예제 #13
0
        private ResolveDelegate ResolveContextResolveInterceptor(ResolveDelegate next)
        {
            return(async(originInstance, identifier, context, frame) =>
            {
                IIxInstanceLock instance =
                    _argumentProvider.TryGetInstance(identifier, context);

                // ReSharper disable once ConditionIsAlwaysTrueOrFalse
                if (instance == null)
                {
                    return await next(originInstance, identifier, context, frame);
                }

                return instance;
            });
        }
예제 #14
0
        /// <inheritdoc/>
        public void AddLock(IIxInstanceLock instanceLock)
        {
            if (instanceLock == null)
            {
                throw new ArgumentNullException(nameof(instanceLock));
            }

            EnsureTreeLocked();

            bool inserted = _locks.Add(instanceLock);

            Critical.Assert(inserted, "Lock already registered in the target instance.");

            UpdateDisposeSuspendState();

            UpdateChildrenDisposeCompleteSuspendState();
        }
예제 #15
0
        /// <summary>
        /// Initializes a new instance of the <see cref="IxInstance"/> class.
        /// </summary>
        /// <remarks>
        /// Instance creates in the "Half-instantiated state".
        /// </remarks>
        /// <param name="providerNode">Node that produces instance.</param>
        /// <param name="parentInstance">Direct parent instance.</param>
        /// <param name="creatorTempLock">First temp lock for the creator of a new instance.</param>
        public IxInstance(
            IxProviderNode providerNode,
            [CanBeNull] IIxInstance parentInstance,
            out IIxInstanceLock creatorTempLock)
            : base(providerNode.Host.InstanceTreeSyncRoot)
        {
            ProviderNode              = providerNode;
            _parentInstance           = parentInstance;
            _ownedLocks               = new ProcessableSet <IIxInstanceLock>();
            _locks                    = new ProcessableSet <IIxInstanceLock>();
            _childrenDisposeCompleted = new AwaitableEvent();
            if (parentInstance != null)
            {
                new IxInstanceChildLock(parentInstance, this);
            }

            creatorTempLock = new IxInstancePinLock(this);
            _initTempLock   = creatorTempLock;
        }
예제 #16
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;
            }
        }
예제 #17
0
 void IIxInstance.RemoveOwnedLock(IIxInstanceLock instanceLock)
 {
     // Do nothing.
 }
예제 #18
0
 void IIxInstance.AddOwnedLock(IIxInstanceLock instanceLock)
 {
     // Do nothing.
 }
예제 #19
0
 void IIxInstance.RemoveOwnedLock(IIxInstanceLock instanceLock)
 {
     Critical.Assert(false, "This is completely virtual object and cannot own locks.");
 }