以下是可重复使用的异步处理支持解决方案。由于.NET Core 3.0尚未发布,我将为当前C#版本(7.3)和测试版(8.0)提供代码。
一旦在对象上调用, 它不会阻塞并将确保一旦所有任务完成就进行处理。
源代码(当前C#版本,不包括IAsyncDisposable):
相关使用:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
所有跟踪任务完成后可以处理的接口:
public interface ITrackingDisposable : IDisposable
{
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;
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();
}
}
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();
}
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();
}
}
}
一个简化实现的基类:
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...");
}
}
using
语句中正确地await
你的async
方法。有关详细信息,请参阅此博客文章。 - Simply Ged