我正在尝试使用 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);
}
}