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