Чтобы получить необходимый метод, вам необходимо создать пользовательский awaiter. В основном это шаблон, ключ - это просто, что, когда его просят добавить продолжение, вы добавляете его с использованием текущего контекста синхронизации для успешного завершения и используя планировщик по умолчанию, когда он не запускается до завершения.
public struct CaptureContextOnSuccessAwaiter : INotifyCompletion
{
private Task task;
public CaptureContextOnSuccessAwaiter(Task task)
{
this.task = task;
}
public CaptureContextOnSuccessAwaiter GetAwaiter() { return this; }
public void OnCompleted(Action continuation)
{
if (SynchronizationContext.Current != null)
{
task.ContinueWith(t => continuation(),
CancellationToken.None,
TaskContinuationOptions.OnlyOnRanToCompletion,
TaskScheduler.FromCurrentSynchronizationContext());
task.ContinueWith(t => continuation(),
CancellationToken.None,
TaskContinuationOptions.NotOnRanToCompletion,
TaskScheduler.Default);
}
else
{
task.ContinueWith(t => continuation(),
CancellationToken.None,
TaskContinuationOptions.None,
TaskScheduler.Default);
}
}
public void GetResult() { task.GetAwaiter().GetResult(); }
public bool IsCompleted { get { return task.GetAwaiter().IsCompleted; } }
}
public struct CaptureContextOnSuccessAwaiter<T> : INotifyCompletion
{
private Task<T> task;
public CaptureContextOnSuccessAwaiter(Task<T> task)
{
this.task = task;
}
public CaptureContextOnSuccessAwaiter<T> GetAwaiter() { return this; }
public void OnCompleted(Action continuation)
{
if (SynchronizationContext.Current != null)
{
task.ContinueWith(t => continuation(),
CancellationToken.None,
TaskContinuationOptions.OnlyOnRanToCompletion,
TaskScheduler.FromCurrentSynchronizationContext());
task.ContinueWith(t => continuation(),
CancellationToken.None,
TaskContinuationOptions.NotOnRanToCompletion,
TaskScheduler.Default);
}
else
{
task.ContinueWith(t => continuation(),
CancellationToken.None,
TaskContinuationOptions.None,
TaskScheduler.Default);
}
}
public T GetResult() { return task.GetAwaiter().GetResult(); }
public bool IsCompleted { get { return task.GetAwaiter().IsCompleted; } }
}
public static CaptureContextOnSuccessAwaiter ContextIfSuccess(this Task task)
{
return new CaptureContextOnSuccessAwaiter(task);
}
public static CaptureContextOnSuccessAwaiter<T> ContextIfSuccess<T>(this Task<T> task)
{
return new CaptureContextOnSuccessAwaiter<T>(task);
}
Почему детали реализации, такие как 'SynchronizationContext' имеет значение для вас? –
Потому что я не хочу прерывать тему пользовательского интерфейса без причины, особенно на мобильных устройствах. – Miles
Затем используйте асинхронный буфер для регистрации? log4j предоставляет это из коробки. Кроме того, это действительно заметный успех? –