1

我正在尝试使用 Action 委托类型来在第 3 方 COM dll 中调用的方法挂断时强制超时。经过大量搜索,我发现我可以使用 Action<> 或 Func<> 并传递多达 4 个通用参数,具体取决于调用的方法是否返回参数。

对于这种情况,我希望对一系列返回 void 并采用 2 个参数的方法调用超时。下面是我整理的代码,但我无法确定如何正确编码 BeginInvoke,提示我放置“T arg1”和“T arg2”但是当我输入 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,在这种情况下,这意味着在我进行第二次调用时它还没有中止。

    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 回答