1

サードパーティのCOMdllで呼び出されたメソッドがハングアップしたときに、タイムアウトを強制するために使用するActionデリゲートタイプの使用に頭を悩ませようとしています。多くの検索を行った後、Action<>またはFunc<>を使用して、呼び出されたメソッドがパラメーターを返すかどうかに応じて、最大4つの汎用パラメーターを渡すことができることがわかりました。

この例では、voidを返し、2つのパラメーターを受け取る一連のメソッドでタイムアウトを呼び出したいと思います。以下は私がまとめているコードですが、BeginInvokeを正しくコーディングする方法を決定できません。「Targ1」と「Targ2」を配置するように求められますが、param1またはparam2を入力すると、VS2008はこれらを通知します。値は不確定です。

これまでのコードは次のとおりです。

static void CallAndWait(Action<T, T> action, int timeout)
{
    Thread subThread = null;
    Action<T, T> wrappedAction = (param1, param2) =>
    {
        subThread = Thread.CurrentThread;
        action(param1, param2);
    };

    IAsyncResult result = wrappedAction.BeginInvoke(param1, param2, null, null);
    if (((timeout != -1) && !result.IsCompleted) &&
    (!result.AsyncWaitHandle.WaitOne(timeout, false) || !result.IsCompleted))
    {
        if (subThread != null)
        {
            subThread.Abort();
        }

        //TODO: close external resource.

        throw new TimeoutException();
    }
    else
    {
        action.EndInvoke(result);
    }
}

ここで何が間違っているかについてのアイデアは大歓迎です。

以下は、最初のコメントに基づいて再編集されたコードです

これまでの入力に感謝します。以下をコンパイルします。私はそれを呼び出す際に構文を正しく理解できないようです。

public static void CallAndWait<T1, T2>(Action<T1, T2> action, int timeout)
{
    Thread subThread = null;
    T1 param1 = default(T1);
    T2 param2 = default(T2);

    Action<T1, T2> wrappedAction = (p1, p2) =>
    {
        subThread = Thread.CurrentThread;
        action(param1, param2);
    };

    IAsyncResult result = wrappedAction.BeginInvoke(param1, param2, null, null);
    if (((timeout != -1) && !result.IsCompleted) &&
    (!result.AsyncWaitHandle.WaitOne(timeout, false) || !result.IsCompleted))
    {
        if (subThread != null)
        {
            subThread.Abort();
        }

        //TODO: close external resource.

        throw new TimeoutException();
    }
    else
    {
        action.EndInvoke(result);
    }
}

次のメソッドを呼び出して、これをテストしようとしています。

public void LongTimeProcess(int a, string b)
{
    Thread.Sleep(a);
}

しかし、次のコードは正しくありません。

    Action<int, string> action = (s1, s2) => LongTimeProcess(s1, s2);
    CallAndWait<int, string>(action(1500, "hello"), 500);

更新 されたコードフォーラムユーザーが将来参照できるようにコードを投稿しました。以下のコードは機能しているようです。チェックする唯一のポイントは、結果がアクションに関連付けられていないため、同じ関数で「action.EndInvoke(result)」を実行するときに、ユニットテストによって例外がスローされることです。これはおそらく、私のLongProcessが単なるThread.sleepであるためです。これは、この場合、2回目の呼び出しが行われるまでに中止されていないことを意味します。

    public static void CallAndWait<T1, T2>(Action<T1, T2> action, T1 arg1, T2 arg2, int timeout)

    {
        Thread subThread = null;
        Action<T1, T2> wrappedAction = (p1, p2) =>
        {
            subThread = Thread.CurrentThread;
            action(arg1, arg2);
        };

        IAsyncResult result = wrappedAction.BeginInvoke(arg1, arg2, null, null);
        if (((timeout != -1) && !result.IsCompleted) &&
        (!result.AsyncWaitHandle.WaitOne(timeout, false) || !result.IsCompleted))
        {
            if (subThread != null)
            {
                subThread.Abort();
            }

            //TODO: close external resource.

            throw new TimeoutException();
        }
        else
        {
            action.EndInvoke(result);
        }
    }
4

1 に答える 1

1

最初はおそらく

static void CallAndWait<T>(Action<T, T> action, int timeout)

それ以外の

static void CallAndWait(Action<T, T> action, int timeout)

また、パラメータのタイプが異なる場合は、次のようになります。

static void CallAndWait<T1, T2>(Action<T1, T2> action, int timeout)

しかし、それだけではないと思います。もう一度見ていきます。

アップデート

今、私はあなたの問題を見ることができます...あなたが電話をかけようとするとあなたはアクションを呼んでいますCallAndWait()。呼び出しは次のようにする必要があります

CallWithTimeout.CallAndWait(action, 1500, "hello", 500);

あなたの電話の代わりに。

CallWithTimeout.CallAndWait<int, string>(action(1500, "hello"), 500);

したがって、メソッドシグネチャをから変更する必要があります

void CallAndWait<T1, T2>(Action<T1, T2> action, int timeout)

void CallAndWait<T1, T2>(Action<T1, T2> action, T1 arg1, T2 arg2, int timeout)

本体を少し変更すれば完了です。

于 2009-09-09T11:00:00.673 に答える