.net 使用RX进行异常重试

.net 使用RX进行异常重试,.net,winforms,exception-handling,system.reactive,.net,Winforms,Exception Handling,System.reactive,我正在尝试一种有趣的模式,使用RX扩展进行异常重试。我有以下代码 Public Async Function InitializeCommunications() As Task Await Observable.Create(Of Unit)(Async Function(observer) MessageBox.Show("Please press reset")

我正在尝试一种有趣的模式,使用RX扩展进行异常重试。我有以下代码

Public Async Function InitializeCommunications() As Task
    Await Observable.Create(Of Unit)(Async Function(observer)
                                         MessageBox.Show("Please press reset")
                                         Await Me.Cockpit.LoadDriverToPLC()
                                         MessageBox.Show("Please press start")
                                         observer.OnNext(Unit.Default)
                                     End Function).Retry()
End Function
该代码几乎完美地工作。如果LoadDriverToPLC中引发异常 然后,序列被重新订阅,正文重新运行,并要求用户 再次按“重置”

这段代码只有一个问题。第一次通过MessageBox调用 是正确的模态。这意味着他们坐在主窗口上方,你无法隐藏他们 不小心点击了主窗口。但是,如果引发异常并且 如果重试body,则MessageBox调用不再是模态调用

我确信这与RX计划有关。确保身体健康的诀窍是什么 总是在相同的上下文中运行吗

我打算稍后将这个模式包装起来,当我可以将它可靠地转换为

Public Async Function InitializeCommunications() As Task
    Await RetryOn(of Exception)(Async Sub()
                                         MessageBox.Show("Please press reset")
                                         Await Me.Cockpit.LoadDriverToPLC()
                                         MessageBox.Show("Please press start")
                                End Sub)
End Function

解决方案似乎是捕获同步上下文和 强制观察者在正确的上下文中得到通知,以便 使用相同的上下文重试

Public Async Function InitializeCommunications(msgFeedback As Func(Of String, Task)) As Task
    Dim context = SynchronizationContext.Current
    Await Observable.Create(Of Unit)(
             Async Function(observer)
                 MessageBox.Show("Please press reset")
                 Await Me.Cockpit.LoadMessageLoopToPLC(111)
                 MessageBox.Show("Please press start")
                 observer.OnNext(Unit.Default)
             End Function).ObserveOn(context).Retry()
End Function
另一种可能更好的方法是在对象上创建一些扩展方法,如下所示

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FunctionalExtensions
{
    public static class ObjectMixins
    {
        public static T Retry<Ex, T>(this Object This, int count, Func<T> action)
        where  Ex : Exception
        {
            while (true)
            {
                try
                {
                    return action();
                }
                catch(Ex)
                {
                    if (count==0)
                    {
                        throw;
                    }
                    count--;
                }
            }
        }

        public static async Task<T> Retry<Ex, T>(this Object This, int count, Func<Task<T>> action)
        where  Ex : Exception
        {
            while (true)
            {
                try
                {
                    return await action();
                }
                catch(Ex)
                {
                    if (count==0)
                    {
                        throw;
                    }
                    count--;
                }
            }
        }

        public static void Retry<Ex>(this Object This, int count, Action action)
        where  Ex : Exception
        {
            This.Retry<Ex, bool>(count, () => { action(); return true; });
        }

        public static async Task Retry<Ex>(this Object This, int count, Func<Task> action)
        where  Ex : Exception
        {
            await This.Retry<Ex, bool>(count, async () => { await action(); return true; });
        }

        public static void Retry<Ex>(this Object This, Action action)
        where  Ex : Exception
        {
            This.Retry<Ex, bool>(() => { action(); return true; });
        }

        public static T Retry<Ex, T>(this Object This, Func<T> action)
        where Ex : Exception
        {
            while (true)
            {
                try
                {
                    return action();
                }
                catch(Ex)
                {
                }
            }
        }

    }
}

解决方案似乎是捕获同步上下文和 强制观察者在正确的上下文中得到通知,以便 使用相同的上下文重试

Public Async Function InitializeCommunications(msgFeedback As Func(Of String, Task)) As Task
    Dim context = SynchronizationContext.Current
    Await Observable.Create(Of Unit)(
             Async Function(observer)
                 MessageBox.Show("Please press reset")
                 Await Me.Cockpit.LoadMessageLoopToPLC(111)
                 MessageBox.Show("Please press start")
                 observer.OnNext(Unit.Default)
             End Function).ObserveOn(context).Retry()
End Function
另一种可能更好的方法是在对象上创建一些扩展方法,如下所示

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FunctionalExtensions
{
    public static class ObjectMixins
    {
        public static T Retry<Ex, T>(this Object This, int count, Func<T> action)
        where  Ex : Exception
        {
            while (true)
            {
                try
                {
                    return action();
                }
                catch(Ex)
                {
                    if (count==0)
                    {
                        throw;
                    }
                    count--;
                }
            }
        }

        public static async Task<T> Retry<Ex, T>(this Object This, int count, Func<Task<T>> action)
        where  Ex : Exception
        {
            while (true)
            {
                try
                {
                    return await action();
                }
                catch(Ex)
                {
                    if (count==0)
                    {
                        throw;
                    }
                    count--;
                }
            }
        }

        public static void Retry<Ex>(this Object This, int count, Action action)
        where  Ex : Exception
        {
            This.Retry<Ex, bool>(count, () => { action(); return true; });
        }

        public static async Task Retry<Ex>(this Object This, int count, Func<Task> action)
        where  Ex : Exception
        {
            await This.Retry<Ex, bool>(count, async () => { await action(); return true; });
        }

        public static void Retry<Ex>(this Object This, Action action)
        where  Ex : Exception
        {
            This.Retry<Ex, bool>(() => { action(); return true; });
        }

        public static T Retry<Ex, T>(this Object This, Func<T> action)
        where Ex : Exception
        {
            while (true)
            {
                try
                {
                    return action();
                }
                catch(Ex)
                {
                }
            }
        }

    }
}