Patrick Skelton Ответов: 0

Как написать универсальный обработчик событий?


Я пытался следить за этой статьей здесь Тайм-Аут Задачи Крафта о том, как создать метод расширения утилиты для добавления тайм-аута к задаче.

Мой код (с некоторыми пропусками) показан ниже. Он показывает две версии функциональности таймаута, одну не универсальную и одну универсальную.

Как вы можете видеть, я попытался реализовать делегат, который передается в 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 говорит, что он "не может преобразовать группу методов в действие "объект".

0 Ответов