实现带参数调用泛型函数的超时

发布于 2024-08-05 01:50:14 字数 3319 浏览 2 评论 0原文

我试图了解如何使用 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);
        }
    }

I am trying to get my head around the use of the Action delegate type for use in forcing a timeout when methods called in a 3rd party COM dll hang up. After much searching I find that I can use Action<> or Func<> and pass up to 4 generic parameters depending on whether the method called returns a parameter or not.

For this instance I wish to call a timeout on a series of methods that return void and take 2 parameters. What follows is the code that I am putting together, but I am unable to determine how to correctly code the BeginInvoke, I am prompted to place "T arg1" and "T arg2" but when I enter param1 or param2 VS2008 tells me that these values are indeterminate.

Here is the code as it is so far:

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

Any ideas on what is wrong here would be much appreciated.

Below is a re-edited code based on the first comment

Thanks for the input so far. The following compiles. I just can't seem to get the syntax right in calling it.

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

I am trying to test this by calling the following method with it:

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

But the following code is not correct:

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

Updated code
I've posted the code for future reference by forum users. The code below appears to work.
The only point to check is that my unit test causes an exception to be thrown when calling the routine a second time on the same function at the point where we "action.EndInvoke(result)" as the result is not associated with the action. This is probably because my LongProcess is just a Thread.sleep, which in this instance will mean that it hasn't aborted by the time that my second call is made.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

千寻… 2024-08-12 01:50:15

起初它可能应该

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

代替

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

and 如果参数具有不同的类型,甚至以下。

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)

修改主体,您应该完成。

At first it should probably be

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

instead of

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

and if the parameters have different types even the following.

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

But I don't think that is all. Going to look at it again.

UPDATE

Now I can see your problem ... you are calling the action when you try to call CallAndWait(). The call must be the following

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

instead of your call.

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

So you have to change the method signature from

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

to

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

modify the body a bit and you should be done.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文