这是可重用异步处理支持的解决方案。由于 .NET Core 3.0 尚未发布,我将提供当前 C# 版本 (7.3) 和 beta (8.0) 的代码。
一旦在对象上调用IDisposable.Dispose(),它就不会阻塞,并确保所有任务完成后立即处理。
源代码(当前 C# 版本,不含IAsyncDisposable)
使用相关:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
所有跟踪任务完成后可以处理的界面:
public interface ITrackingDisposable : IDisposable
{
//The implementation of the actual disposings
Task FinishDisposeAsync();
}
跟踪所有正在运行的任务并在适当的时间调用延迟处理的处理器:
public class TrackingDisposer : IDisposable
{
private readonly LinkedList<Task> _tasks = new LinkedList<Task>();
private readonly ITrackingDisposable _target;
public bool IsDisposed { get; private set; } = false;
//The supported class must implement ITrackingDisposable
public TrackingDisposer(ITrackingDisposable target)
=> _target = target ?? throw new ArgumentNullException();
//Add a task to the tracking list, returns false if disposed
//Without return value
public bool Track(Func<Task> func, out Task result)
{
lock (_tasks)
{
if (IsDisposed)
{
result = null;
return false;
}
var task = func();
var node = _tasks.AddFirst(task);
async Task ending()
{
await task;
var dispose = false;
lock (_tasks)
{
_tasks.Remove(node);
dispose = IsDisposed && _tasks.Count == 0;
}
if (dispose)
{
await _target.FinishDisposeAsync();
}
}
result = ending();
}
return true;
}
//With return value
public bool Track<TResult>(Func<Task<TResult>> func, out Task<TResult> result)
{
lock (_tasks)
{
if (IsDisposed)
{
result = null;
return false;
}
var task = func();
var node = _tasks.AddFirst(task);
async Task<TResult> ending()
{
var result = await task;
var dispose = false;
lock (_tasks)
{
_tasks.Remove(node);
dispose = IsDisposed && _tasks.Count == 0;
}
if (dispose)
{
await _target.FinishDisposeAsync();
}
return result;
}
result = ending();
}
return true;
}
//The entry of applying for dispose
public void Dispose()
{
var dispose = false;
lock (_tasks)
{
if (IsDisposed)
{
return;
}
IsDisposed = true;
dispose = _tasks.Count == 0;
}
if (dispose)
{
_target.FinishDisposeAsync();
}
}
}
一个简化实现的基类:
public abstract class TrackingDisposable : ITrackingDisposable
{
private readonly TrackingDisposer _disposer;
public TrackingDisposable()
=> _disposer = new TrackingDisposer(this);
protected virtual void FinishDispose() { }
protected virtual Task FinishDisposeAsync()
=> Task.CompletedTask;
Task ITrackingDisposable.FinishDisposeAsync()
{
FinishDispose();
return FinishDisposeAsync();
}
public void Dispose()
=> _disposer.Dispose();
protected Task Track(Func<Task> func)
=> _disposer.Track(func, out var result)
? result
: throw new ObjectDisposedException(nameof(TrackingDisposable));
protected Task<TResult> Track<TResult>(Func<Task<TResult>> func)
=> _disposer.Track(func, out var result)
? result
: throw new ObjectDisposedException(nameof(TrackingDisposable));
}
演示和测试输出
测试类:
internal sealed class TestDisposingObject : TrackingDisposable
{
public Task Job0Async() => Track(async () =>
{
await Task.Delay(200);
Console.WriteLine("Job0 done.");
});
public Task<string> Job1Async(int ms) => Track(async () =>
{
await Task.Delay(ms);
return "Job1 done.";
});
protected override void FinishDispose()
=> Console.WriteLine("Disposed.");
}
主要:
internal static class Program
{
private static async Task Main()
{
var result0 = default(Task);
var result1 = default(Task);
var obj = new TestDisposingObject();
result0 = obj.Job0Async();
result1 = obj.Job1Async(100).ContinueWith(r => Console.WriteLine(r.Result));
obj.Dispose();
Console.WriteLine("Waiting For jobs done...");
await Task.WhenAll(result0, result1);
}
}
输出:
Waiting For jobs done...
Job1 done.
Job0 done.
Disposed.
附加,C# 8.0(带有IAsyncDisposable)
将类型定义替换为:
public interface ITrackingDisposable : IDisposable, IAsyncDisposable
{
Task FinishDisposeAsync();
}
public class TrackingDisposer : IDisposable, IAsyncDisposable
{
private readonly LinkedList<Task> _tasks = new LinkedList<Task>();
private readonly ITrackingDisposable _target;
private readonly TaskCompletionSource<object> _disposing = new TaskCompletionSource<object>();
public bool IsDisposed { get; private set; } = false;
public TrackingDisposer(ITrackingDisposable target)
=> _target = target ?? throw new ArgumentNullException();
public bool Track(Func<Task> func, out Task result)
{
lock (_tasks)
{
if (IsDisposed)
{
result = null;
return false;
}
var task = func();
var node = _tasks.AddFirst(task);
async Task ending()
{
await task;
var dispose = false;
lock (_tasks)
{
_tasks.Remove(node);
dispose = IsDisposed && _tasks.Count == 0;
}
if (dispose)
{
await _target.FinishDisposeAsync();
_disposing.SetResult(null);
}
}
result = ending();
}
return true;
}
public bool Track<TResult>(Func<Task<TResult>> func, out Task<TResult> result)
{
lock (_tasks)
{
if (IsDisposed)
{
result = null;
return false;
}
var task = func();
var node = _tasks.AddFirst(task);
async Task<TResult> ending()
{
var result = await task;
var dispose = false;
lock (_tasks)
{
_tasks.Remove(node);
dispose = IsDisposed && _tasks.Count == 0;
}
if (dispose)
{
await _target.FinishDisposeAsync();
_disposing.SetResult(null);
}
return result;
}
result = ending();
}
return true;
}
public void Dispose()
{
var dispose = false;
lock (_tasks)
{
if (IsDisposed)
{
return;
}
IsDisposed = true;
dispose = _tasks.Count == 0;
}
if (dispose)
{
_target.FinishDisposeAsync();
_disposing.SetResult(null);
}
}
public ValueTask DisposeAsync()
{
Dispose();
return new ValueTask(_disposing.Task);
}
}
public abstract class TrackingDisposable : ITrackingDisposable
{
private readonly TrackingDisposer _disposer;
public TrackingDisposable()
=> _disposer = new TrackingDisposer(this);
protected virtual void FinishDispose() { }
protected virtual Task FinishDisposeAsync()
=> Task.CompletedTask;
Task ITrackingDisposable.FinishDisposeAsync()
{
FinishDispose();
return FinishDisposeAsync();
}
public void Dispose()
=> _disposer.Dispose();
public ValueTask DisposeAsync() => _disposer.DisposeAsync();
protected Task Track(Func<Task> func)
=> _disposer.Track(func, out var result)
? result
: throw new ObjectDisposedException(nameof(TrackingDisposable));
protected Task<TResult> Track<TResult>(Func<Task<TResult>> func)
=> _disposer.Track(func, out var result)
? result
: throw new ObjectDisposedException(nameof(TrackingDisposable));
}
测试主要:
internal static class Program
{
private static async Task Main()
{
await using var obj = new TestDisposingObject();
_ = obj.Job0Async();
_ = obj.Job1Async(100).ContinueWith(r => Console.WriteLine(r.Result));
Console.WriteLine("Waiting For jobs done...");
}
}