1

例外の再試行に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で例外がスローされた場合、シーケンスが再サブスクライブされ、本体が再実行され、ユーザーはリセットをもう一度押すように求められます。

このコードには1つだけ問題があります。初めてのMessageBox呼び出しは、正しくモーダルです。つまり、メインウィンドウの上に乗っており、誤ってメインウィンドウをクリックして非表示にすることはできません。ただし、例外がスローされて本文が再試行された場合、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
4

1 に答える 1

1

解決策は、同期コンテキストをキャプチャし、オブザーバーに正しいコンテキストで通知するように強制することであると思われるため、同じコンテキストを使用して再試行します

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)
                {
                }
            }
        }

    }
}

同期および非同期操作をサポートします。以下のように使用して、例外をスローする前に10回再試行できます

Public Async Function InitializeCommunications(msgFeedback As Func(Of String, Task)) As Task
    Await Retry(Of Exception)(10, 
        Async Function()
          MessageBox.Show("Please press reset on the NUM control unit then press ok here.")
          Await Me.Cockpit.LoadMessageLoopToPLC(111)
          MessageBox.Show("Please press start on control unit.")
       End Function)
End Function
于 2012-11-20T07:36:56.213 に答える