If I have a class where a field is an instance of a Task
, and that task returns a class which implements IDisposable
, what is a pattern to implement IDisposable
(+/- IAsyncDisposable
) on the instance wrapped by the Task
, bearing in mind the Task may have completed, may still be in progress and require cancellation, or may have failed by the time Dispose is called. A quick go in pseudo code:
public sealed Class MyClass : IDisposable
{
private readonly CancellationTokenSource _cancelTokenSrc;
private readonly Task<SecurityTokens> _securityTask;
private bool _isDisposed;
public MyClass(Uri endPoint) {
_cancelTokenSrc= new CancellationTokenSource;
_securityTask = GetServerSecurityData(endpoint, _cancelTokenSrc.Token);
}
public Task<IEnumerable<File>> GetContainedFiles(string folderName) {
var data = await GetPrivate(...);
...
}
public Task UploadFile(File file) {
var data = await GetPrivate(...);
...
}
public Task<Stream> DowloadFiles(string fileId) {
var data = await GetPrivate(...);
...
}
private async Task<HttpRepsonse> GetPrivate(uri uri) {
var s = await _securityTask;
// now send get request & return response
// include security data contained in s with every request
...
}
///!!! This is where I would appreciate peoples thoughts & expertise!!!
public void Dispose() {
if (!_isDisposed) {
if (_securityTask.IsCompleted) {
_securityTask.Result.Dispose();
}
else if (!_securityTask.IsFaulted && !_securityTask.IsCanceled)
{
_cancelTokenSrc.Cancel();
}
disposed = true;
GC.SupressFinalize()
}
}
}
In summary can you help me implement a more robust dispose() implementation to ensure the Stream returned by the Task is always disposed correctly, plus possibly how to also implement IAsyncDisposable
?
in response to the comments - it is always hard to create a simple example which is easy to follow but which conveys the complexity. In this case I am envisaging the instantiation to begin negotiations with a server to obtain bearer tokens and claims etc. Once this data is available, I don't want to go through the whole authentication/authorization process each time a method is called. Each method will of its own right be asynchronous, but if the security negotiation is ongoing, will await completion of that before initiating a range of different but related methods.
I have changed the example code a little as comments were concentrating on the intention of the pseudocode, which is not really what the question is about - I have tried to make the example a little more concrete. The intent is to create 3 classes all implementing the same interface but negotiating different APIs for accessing the users MS Sharepoint, Google drive or Dropbox files & folders). I can make code to do this - this question is not about working around a specific problem. I would really like to know a useful pattern for disposing the IDisposable
object wrapped by a Task, in a class implementing IDisposable. It may be this is too messy an approach which leads to anti-patterns and that is fine as an answer.
My understanding is that you have a class like this:
public class MyClass
{
public Task<MyDisposable> MyDisposable;
}
And you want to properly manage the IDisposable
lifetime of MyDisposable
.
My standard approach for this is to write methods that let me inject in the code I want to perform on the disposable and then call .Dispose()
before the method ends.
Here are the three that you perhaps need:
public class MyClass
{
private Task<MyDisposable> CreateMyDisposableAsync() => Task.Run(() => new MyDisposable());
public async Task<R> UsingMyDisposableAsync<R>(Func<MyDisposable, Task<R>> consumeAsync)
{
using (var myDisposable = await this.CreateMyDisposableAsync())
{
return await consumeAsync(myDisposable);
}
}
public async IAsyncEnumerable<R> UsingMyDisposableAsync<T, R>(IEnumerable<T> source, Func<MyDisposable, T, Task<R>> consumeAsync)
{
using (var myDisposable = await this.CreateMyDisposableAsync())
{
foreach (var r in source)
{
yield return await consumeAsync(myDisposable, r);
}
}
}
public async Task UsingMyDisposableAsync(Func<MyDisposable, Task> actionAsync)
{
using (var myDisposable = await this.CreateMyDisposableAsync())
{
await actionAsync(myDisposable);
}
}
}
I've implemented this class to show you how these work:
public class MyDisposable : IDisposable
{
public Task<int> GetValueAsync(int t) => Task.Run(() => t * 2);
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
Console.WriteLine("MyDisposable Disposed!");
// TODO: dispose managed state (managed objects)
}
// TODO: free unmanaged resources (unmanaged objects) and override finalizer
// TODO: set large fields to null
disposedValue = true;
}
}
bool disposedValue;
// // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources
// ~MyResource()
// {
// // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
// Dispose(disposing: false);
// }
public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
Note that GetValueAsync
simply doubles the input number.
Now I can write this:
var myClass = new MyClass();
var v = await myClass.UsingMyDisposableAsync<int>(mr => mr.GetValueAsync(42));
Console.WriteLine(v);
await foreach (var x in myClass.UsingMyDisposableAsync<int, int>(
new[] { 1, 2 },
(mr, t) => mr.GetValueAsync(t)))
{
Console.WriteLine(x);
}
int j = 2;
int k = 3;
await myClass.UsingMyDisposableAsync(async mr =>
{
j = await mr.GetValueAsync(j);
k = await mr.GetValueAsync(j + k);
});
Console.WriteLine(j);
Console.WriteLine(k);
That outputs:
MyDisposable Disposed!
84
2
4
MyDisposable Disposed!
MyDisposable Disposed!
4
14
It would have been great to have seen real code from your side so that I could show how this might work for you.