使用参数调用泛型函数实现超时

时间:2009-09-09 10:48:49

标签: c# generics timeout anonymous-methods begininvoke

我正试图在使用Action委托类型时使用,以便在第三方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);
        }
    }

1 个答案:

答案 0 :(得分: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)

稍微修改一下身体就应该完成。