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?
Edit
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.
Edit 2
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:
And you want to properly manage the
IDisposablelifetime ofMyDisposable.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:
I've implemented this class to show you how these work:
Note that
GetValueAsyncsimply doubles the input number.Now I can write this:
That outputs:
It would have been great to have seen real code from your side so that I could show how this might work for you.