view Implab.Fx/PromiseHelpers.cs @ 33:b255e4aeef17

removed the reference to the parent from the promise object this allows resolved promises to release parents and results they are holding. Added complete set of operations to IPromiseBase interface Subscribing to the cancellation event of the promise should not affect it's IsExclusive property More tests.
author cin
date Thu, 10 Apr 2014 02:39:29 +0400
parents 381095ad0a69
children d67b95eddaf4 0fdaf280c797
line wrap: on
line source

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace Implab.Fx
{
    public static class PromiseHelpers
    {
        /// <summary>
        /// Перенаправляет обработку обещания в поток указанного элемента управления.
        /// </summary>
        /// <typeparam name="T">Тип результата обещания</typeparam>
        /// <param name="that">Исходное обещание</param>
        /// <param name="ctl">Элемент управления</param>
        /// <returns>Новое обещание, обработчики которого будут выполнены в потоке элемента управления.</returns>
        /// <exception cref="ArgumentNullException">Параметр не может быть <c>null</c>.</exception>
        /// <example>
        /// client
        ///     .Get("description.txt") // returns a promise
        ///     .DirectToControl(m_ctl) // handle the promise in the thread of the control
        ///     .Then(
        ///         description => m_ctl.Text = description // now it's safe
        ///     )
        /// </example>
        public static Promise<T> DispatchToControl<T>(this Promise<T> that, Control ctl)
        {
            if (that == null)
                throw new ArgumentNullException("that");
            if (ctl == null)
                throw new ArgumentNullException("ctl");

            var directed = new Promise<T>();

            that.Then(
                res =>
                {
                    if (ctl.InvokeRequired)
                        ctl.Invoke(new Action<T>(directed.Resolve), res);
                    else
                        directed.Resolve(res);
                },
                err =>
                {
                    if (ctl.InvokeRequired)
                        ctl.Invoke(new Action<Exception>(directed.Reject), err);
                    else
                        directed.Reject(err);
                }
            );

            return directed;
        }

        /// <summary>
        /// Направляет обработку обещания в текущий поток, если у него существует контекст синхронизации.
        /// </summary>
        /// <typeparam name="T">Тип результата обещания.</typeparam>
        /// <param name="that">Обещание которое нужно обработать в текущем потоке.</param>
        /// <returns>Перенаправленное обещание.</returns>
        public static Promise<T> DispatchToCurrentThread<T>(this Promise<T> that)
        {
            var sync = SynchronizationContext.Current;
            if (sync == null)
                throw new InvalidOperationException("The current thread doesn't have a syncronization context");
            return DispatchToSyncContext(that, sync);
        }

        /// <summary>
        /// Направляет обработку обещания в указанный контекст синхронизации.
        /// </summary>
        /// <typeparam name="T">Тип результата обещания.</typeparam>
        /// <param name="that">Обещание, которое требуется обработать в указанном контексте синхронизации.</param>
        /// <param name="sync">Контекст синхронизации в который будет направлено обещание.</param>
        /// <returns>Новое обещание, которое будет обрабатываться в указанном контексте.</returns>
        public static Promise<T> DispatchToSyncContext<T>(this Promise<T> that, SynchronizationContext sync)
        {
            if (that == null)
                throw new ArgumentNullException("that");
            if (sync == null)
                throw new ArgumentNullException("sync");

            var d = new Promise<T>();

            that.Then(
                res => sync.Post(state => d.Resolve(res), null),
                err => sync.Post(state => d.Reject(err), null)
            );

            return d;
        }
    }
}