Как написать универсальный обработчик событий?
Я пытался следить за этой статьей здесь Тайм-Аут Задачи Крафта о том, как создать метод расширения утилиты для добавления тайм-аута к задаче.
Мой код (с некоторыми пропусками) показан ниже. Он показывает две версии функциональности таймаута, одну не универсальную и одну универсальную.
Как вы можете видеть, я попытался реализовать делегат, который передается в
Timer
как отдельная функция. Это нормально в не-универсальной версии, но в универсальной версии актерский состав TaskCompletionSource
не удается, потому что универсальный тип TResult
не является VoidTypeStruct
.Как вы можете видеть, делегат таймера на самом деле не заботится о типе таймера.
TaskCompletionSource
(кроме необходимости знать, как делать актерский состав). Есть ли способ изменить либо мой делегат таймера, либо место, где он передается в new Timer()
чтобы он мог справиться с общей версией функции?Это один из тех разочаровывающих примеров, когда я вижу проблему и вижу, что нужно изменить, но просто не знаю, как это написать.
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; } // This dummy type is needed because there isn't a non-generic TaskCompletionSource. private struct VoidTypeStruct { } internal static void MarshalTaskResults<TResult>( Task source, TaskCompletionSource<TResult> proxy ) { // Code omitted because it is not relevant to this problem. } private static void TimerEventHandler( object state ) { TaskCompletionSource<VoidTypeStruct> tcs = state as TaskCompletionSource<VoidTypeStruct>; // THIS OBVIOUSLY FAILS IN GENERIC VERSION! tcs.TrySetException( new TimeoutException() ); }
Что я уже пробовал:
Я пробовал сделать
TimerEventHandler<t>()
универсальный но тогда конструктор для Timer
говорит, что он "не может преобразовать группу методов в действие "объект".