public ITaskResult Then(Func <NullableResult <object>, object> action)
        {
            var ret = new ManualThreadPoolResult();

            ret.Start();
            var task = CreateTask(ret);

            ThreadPoolResult.OnCompleted(() =>
            {
                var subResult = CreateResult(() =>
                {
                    var nextResult = action(HasResult ? new NullableResult <object>(Result) : new NullableResult <object>());

                    task.Result = nextResult;
                    ret.SetCompleted();
                });

                subResult.OnFailed(error =>
                {
                    ret.SetFailed(error);
                });

                subResult.Start();
            });

            ThreadPoolResult.OnFailed(error =>
            {
                ret.SetFailed(error);
            });

            return(new BoundTaskResult(this, task));
        }
        public ITaskResult Finally(Action <Exception> action)
        {
            var ret = new ManualThreadPoolResult();

            ret.Start();
            var task = CreateTask(ret);

            ThreadPoolResult.OnCompleted(() =>
            {
                var subResult = CreateResult(() =>
                {
                    action(null);
                });

                subResult.OnCompleted(() =>
                {
                    if (HasResult)
                    {
                        task.Result = Result;
                    }
                    ret.SetCompleted();
                });

                subResult.OnFailed(error =>
                {
                    ret.SetFailed(error);
                });

                subResult.Start();
            });

            ThreadPoolResult.OnFailed(error =>
            {
                var subResult = CreateResult(() =>
                {
                    action(error);
                });

                subResult.OnCompleted(() =>
                {
                    ret.SetFailed(error);
                });

                subResult.OnFailed(nested =>
                {
                    ret.SetFailed(ProcessException(ExceptionUtility.AggregateExceptions("finally handler failed", nested, error)));
                });

                subResult.Start();
            });

            return(new BoundTaskResult(this, task));
        }
        public ITaskResult Then(Func <ITaskResult> action)
        {
            var ret = new ManualThreadPoolResult();

            ret.Start();
            var task = CreateTask(ret);

            ThreadPoolResult.OnCompleted(() =>
            {
                var subResult = CreateResult(() =>
                {
                    var next = action();

                    if (next != null)
                    {
                        next.Then(x =>
                        {
                            if (x.HasResult)
                            {
                                task.Result = x.Result;
                            }
                            ret.SetCompleted();
                        }).Finally(error =>
                        {
                            ret.SetFailed(error);
                        }).Start();
                    }
                    else
                    {
                        if (HasResult)
                        {
                            task.Result = Result;
                        }
                        ret.SetCompleted();
                    }
                });

                subResult.OnFailed(error =>
                {
                    ret.SetFailed(error);
                });

                subResult.Start();
            });

            ThreadPoolResult.OnFailed(error =>
            {
                ret.SetFailed(error);
            });

            return(new BoundTaskResult(this, task));
        }
        public ITaskResult Catch(Action <Exception> action)
        {
            var ret = new ManualThreadPoolResult();

            ret.Start();
            var task = CreateTask(ret);

            ThreadPoolResult.OnFailed(error =>
            {
                var subResult = CreateResult(() =>
                {
                    if (!(error is FailureProcessedException))
                    {
                        action(error);
                    }
                });

                subResult.OnCompleted(() =>
                {
                    if (!(error is FailureProcessedException))
                    {
                        ret.SetFailed(new FailureProcessedException("failure caught", error));
                    }
                    else
                    {
                        ret.SetFailed(error);
                    }
                });

                subResult.OnFailed(nested =>
                {
                    ret.SetFailed(ProcessException(ExceptionUtility.AggregateExceptions("catch handler failed", nested, error)));
                });

                subResult.Start();
            });

            ThreadPoolResult.OnCompleted(() =>
            {
                if (HasResult)
                {
                    task.Result = Result;
                }
                ret.SetCompleted();
            });

            return(new BoundTaskResult(this, task));
        }