/// <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)); }
/// <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(); }
void IIxInstance.RemoveLock(IIxInstanceLock instanceLock) { ////throw new NotSupportedException( //// "This is completely virtual object and cannot be locked/unlocked."); // Do nothing. }
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); }); }
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; }); }); }
public IxLock(IIxInstanceLock instanceLock) { Critical.Assert(instanceLock != null, "Lock target should not be null."); _instanceLock = instanceLock; _target = (T)_instanceLock.Target.Object; }
/// <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()); } }
/// <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)); }
/// <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; } }
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); }
/// <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."); } }
/// <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."); } }
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; }); }
/// <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(); }
/// <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; }
/// <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; } }
void IIxInstance.RemoveOwnedLock(IIxInstanceLock instanceLock) { // Do nothing. }
void IIxInstance.AddOwnedLock(IIxInstanceLock instanceLock) { // Do nothing. }
void IIxInstance.RemoveOwnedLock(IIxInstanceLock instanceLock) { Critical.Assert(false, "This is completely virtual object and cannot own locks."); }