Esempio n. 1
0
        protected override async Task <DependencyResult <TDependencyInstance> > ResolveDependencyAsync(IDependencyResolutionContext ctx)
        {
            var specs = ctx.EnsureNotNull(nameof(ctx)).Value.Specs;

            //
            if (specs.DependencyType.IsAssignableFrom(DependencyInstanceType))
            {
                var newInstanceResult = default(DependencyResult <TDependencyInstance>);
                if (specs.IsNewInstanceRequired || !CanShareDependency)
                {
                    try {
                        newInstanceResult = await ResolveNewDependencyInstanceAsync(ctx : ctx).ConfigureAwait(false);

                        if (newInstanceResult.Instance is null)
                        {
                            return(newInstanceResult);
                        }
                        else if (!newInstanceResult.IsNewInstance)
                        {
                            throw
                                new EonException(
                                    message: $"Результат вызова метода '{nameof(ResolveNewDependencyInstanceAsync)}' не соответствует ожидаемому. В частности, свойство результата '{nameof(newInstanceResult)}.{nameof(newInstanceResult.IsNewInstance)}' не соответствует ожидаемому значение '{bool.TrueString}'.");
                        }
                        else if (specs.PreventNewInstanceInitialization)
                        {
                            return(newInstanceResult);
                        }
                        else
                        {
                            await P_InitializeNewDependencyInstanceAsync(instance : newInstanceResult.Instance).ConfigureAwait(false);

                            return(newInstanceResult);
                        }
                    }
                    catch (Exception exception) {
                        if (newInstanceResult.IsNewInstance)
                        {
                            (newInstanceResult.Instance as IDisposable)?.Dispose(exception);
                        }
                        throw;
                    }
                }
                else
                {
                    // В спецификации запроса отсутствует требование разрешения зависимости именно в новый экземпляр (см. specs.IsNewInstanceRequired) + обработчик может "шарить" экземпляр (см. CanShareDependency).
                    //
                    var sharedInstanceStore = ReadDA(ref _sharedInstanceStore);
                    if (sharedInstanceStore is null)
                    {
                        var lck         = ReadDA(ref _sharedInstanceInitializationLock);
                        var lckAcquired = false;
                        try {
                            lckAcquired = await lck.WaitAsync(millisecondsTimeout : TaskUtilities.DefaultAsyncTimeoutMilliseconds).ConfigureAwait(false);

                            if (!lckAcquired)
                            {
                                throw new LockAcquisitionFailException(reason: LockAcquisitionFailReason.TimeoutElapsed);
                            }
                            //
                            sharedInstanceStore = ReadDA(ref _sharedInstanceStore);
                            if (sharedInstanceStore is null)
                            {
                                try {
                                    newInstanceResult = await ResolveNewDependencyInstanceAsync(ctx : ctx).ConfigureAwait(false);

                                    if (newInstanceResult.Instance is null)
                                    {
                                        WriteDA(location: ref _sharedInstanceStore, value: sharedInstanceStore = default(TDependencyInstance).ToValueHolder(ownsValue: false));
                                    }
                                    else if (!newInstanceResult.IsNewInstance)
                                    {
                                        throw
                                            new EonException(
                                                message: $"Результат вызова метода '{nameof(ResolveNewDependencyInstanceAsync)}' не соответствует ожидаемому. В частности, свойство результата '{nameof(newInstanceResult)}.{nameof(newInstanceResult.IsNewInstance)}' не соответствует ожидаемому значение '{bool.TrueString}'.");
                                    }
                                    else if (specs.PreventNewInstanceInitialization)
                                    {
                                        WriteDA(
                                            location: ref _sharedInstanceStore,
                                            value: sharedInstanceStore = newInstanceResult.Instance.ToValueHolder(ownsValue: true));
                                    }
                                    else
                                    {
                                        try {
                                            await P_InitializeNewDependencyInstanceAsync(instance : newInstanceResult.Instance).ConfigureAwait(false);

                                            sharedInstanceStore = newInstanceResult.Instance.ToValueHolder(ownsValue: true);
                                        }
                                        catch (Exception exception) {
                                            sharedInstanceStore = new Vh <TDependencyInstance>(exception: exception);
                                        }
                                        WriteDA(location: ref _sharedInstanceStore, value: sharedInstanceStore);
                                    }
                                }
                                catch (Exception exception) {
                                    if (newInstanceResult.IsNewInstance && !ReferenceEquals(itrlck.Get(ref _sharedInstanceStore)?.ValueDisposeTolerant, newInstanceResult.Instance))
                                    {
                                        (newInstanceResult.Instance as IDisposable)?.Dispose(exception);
                                    }
                                    throw;
                                }
                            }
                        }
                        finally {
                            if (lckAcquired)
                            {
                                try { lck.Release(); }
                                catch (ObjectDisposedException) { }
                            }
                        }
                    }
                    if (sharedInstanceStore.Value is null)
                    {
                        return(DependencyResult <TDependencyInstance> .None);
                    }
                    else
                    {
                        return(new DependencyResult <TDependencyInstance>(instance: sharedInstanceStore.Value, isNewInstance: false));
                    }
                }
            }
            else
            {
                return(DependencyResult <TDependencyInstance> .None);
            }
        }
Esempio n. 2
0
        static void P_Loop(object state)
        {
            var startState = state.EnsureNotNull(nameof(state)).EnsureOfType <P_LoopStartState>().Value;
            //
            var ctx = startState.Context;
            IUnhandledExceptionObserver unhandledExceptionObserver;
            IRunControl       runControl;
            CancellationToken ct;
            Func <CancellationToken, IVh <TCtxState> > stateFactory;
            ManualResetEventSlim     awakeLoopEvent;
            Queue <P_InvokeItemBase> queue;
            PrimitiveSpinLock        queueSpinLock;

            try {
                unhandledExceptionObserver = ctx.P_UnhandledExceptionObserver;
                runControl     = ctx.RunControl;
                ct             = ctx.P_Ct;
                stateFactory   = ctx.P_StateFactory;
                awakeLoopEvent = ctx.P_AwakeLoopEvent;
                queue          = ctx.P_InvokeQueue;
                queueSpinLock  = ctx.P_InvokeQueueSpinLock;
            }
            catch (ObjectDisposedException) {
                return;
            }
            var bypassUnhandledExceptionObserver = false;

            try {
                Exception caughtException1 = default;
                try {
                    ctx.P_IsLoopAlive = true;
                    startState.LoopStartedEvent.Set();
                    //
                    IVh <TCtxState> ctxState         = default;
                    Exception       caughtException2 = default;
                    try {
                        // Создание объекта состояния контекста.
                        //
                        try {
                            ctxState = stateFactory(arg: ct);
                        }
                        catch (Exception exception) {
                            ctxState = new Vh <TCtxState>(exception: exception);
                        }
                        // Цикл обработки очереди.
                        //
                        for (; ;)
                        {
                            if (runControl.HasStopRequested || ct.IsCancellationRequested)
                            {
                                break;
                            }
                            //
                            P_InvokeItemBase queueItem = default;
                            try {
                                queueItem = queueSpinLock.Invoke(() => queue.Count > 0 ? queue.Dequeue() : null);
                                if (!(queueItem is null))
                                {
                                    if (queueItem.IsInvokeCompleted)
                                    {
                                        continue;
                                    }
                                    else
                                    {
                                        try {
                                            itrlck.Set(ref ctx._currentInvoke, queueItem);
                                            queueItem.Invoke(ctx: ctx, ctxState: ctxState);
                                        }
                                        catch (Exception exception) {
                                            if (bypassUnhandledExceptionObserver)
                                            {
                                                throw;
                                            }
                                            else
                                            {
                                                bool isExceptionObserved;
                                                try {
                                                    isExceptionObserved = unhandledExceptionObserver.ObserveException(exception: exception, component: queueItem);
                                                }
                                                catch (Exception secondException) {
                                                    bypassUnhandledExceptionObserver = true;
                                                    throw new AggregateException(exception, secondException);
                                                }
                                                if (!isExceptionObserved)
                                                {
                                                    bypassUnhandledExceptionObserver = true;
                                                    throw;
                                                }
                                            }
                                        }
                                    }
                                    finally {
                                        itrlck.SetNull(ref ctx._currentInvoke, queueItem);
                                    }
                                    continue;
                                }
                            }
                            catch (Exception exception) {
                                try { queueItem.TrySetInvokeResultAsCanceled(); }
                                catch (Exception secondException) {
                                    throw new AggregateException(exception, secondException);
                                }
                                throw;
                            }
                            // Ожидание.
                            //
                            if (awakeLoopEvent.IsSet)
                            {
                                awakeLoopEvent.Reset();
                            }
                            else
                            {
                                awakeLoopEvent.Wait(millisecondsTimeout: 937);
                            }
                        }
                    }
                    catch (Exception exception) {
                        caughtException2 = exception;
                        throw;
                    }
                    finally {
                        ctxState?.Dispose(exception: caughtException2);
                    }
                }