I have been trying to follow the article here
Crafting Task Timeout on how to create a utility extension method to add a timeout to a Task.
My code (with some omissions) is shown below. It shows two versions of the timeout functionality, one non-generic and one generic.
As you can see, I have tried to implement the delegate that is passed into the
Timer
as a separate function. This is fine in the non-generic version but in the generic version, the cast of the
TaskCompletionSource
fails because the generic type
TResult
is not a
VoidTypeStruct
.
As you can see, the timer delegate doesn't actually care about the type of the
TaskCompletionSource
(other than needing to know how to do the cast). Is there a way to modify either my timer delegate or the place where it is passed into the
new Timer()
so that it can cope with the generic version of the function?
This is one of those frustrating examples where I can see the problem and I can see what needs to change but I just don't know how to write it.
public static Task TimeoutAfter( this Task task, int millisecondsTimeout )
{
TaskCompletionSource<VoidTypeStruct> tcs = new TaskCompletionSource<VoidTypeStruct>();
Timer timer = new Timer( TimerEventHandler, tcs, millisecondsTimeout, true );
timer.Start();
task.ContinueWith( ( antecedent, state ) =>
{
var stateTuple = (Tuple<Timer,TaskCompletionSource<VoidTypeStruct>>)state;
stateTuple.Item1.Dispose();
MarshalTaskResults( antecedent, stateTuple.Item2 );
},
Tuple.Create<ITimer,TaskCompletionSource<VoidTypeStruct>>( timer, tcs ),
CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default );
return tcs.Task;
}
public static Task<TResult> TimeoutAfter<TResult>( this Task<TResult> task, int millisecondsTimeout )
{
TaskCompletionSource<TResult> tcs = new TaskCompletionSource<TResult>();
Timer timer = new Timer( TimerEventHandler, tcs, millisecondsTimeout, true );
timer.Start();
task.ContinueWith( ( antecedent, state ) =>
{
var stateTuple = (Tuple<ITimer,TaskCompletionSource<TResult>>)state;
stateTuple.Item1.Dispose();
MarshalTaskResults( antecedent, stateTuple.Item2 );
},
Tuple.Create<ITimer,TaskCompletionSource<TResult>>( timer, tcs ),
CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default );
return tcs.Task;
}
private struct VoidTypeStruct { }
internal static void MarshalTaskResults<TResult>( Task source, TaskCompletionSource<TResult> proxy )
{
}
private static void TimerEventHandler( object state )
{
TaskCompletionSource<VoidTypeStruct> tcs = state as TaskCompletionSource<VoidTypeStruct>;
tcs.TrySetException( new TimeoutException() );
}
What I have tried:
I have tried making the
TimerEventHandler<t>()
generic but then the constructor for the
Timer
says it 'Cannot convert method group to Action<object>'.