I want to return a Func middle of a using block. Should I worry about disposing of, before the user runs the result Func?
A sample code:
private IDbContextTransaction _transaction;
public Func<Task> BeginTransaction()
{
Task lockDispose = CommitTransaction();
using (_transaction = _dbContext.Database.BeginTransaction())
{
return async() =>
{
await lockDispose;
};
Task.WaitAll(lockDispose); //This code is unreachable.
}
}
private async Task CommitTransaction()
{
_transaction.Commit();
await Task.CompletedTask;
}
Note that the execution time of the result Func is up to the user of this service.
I checked This Question and it's not my answer.
Since you want your user to be able to work with the connection between calling BeginTransaction
and CommitTransaction
, then the only thing you can do is to move disposal outside of this scope:
private IDbContextTransaction _transaction;
public Func<Task> BeginTransaction()
{
_transaction = _dbContext.Database.BeginTransaction()
return CommitTransaction;
}
private async Task CommitTransaction()
{
_transaction.Commit();
_transaction.Dispose();
await Task.CompletedTask;
}
// I advice you implement IDisposable fully, but
// this will do for the sake of demonstration
public void Dispose()
{
_transaction?.Dispose();
}
And then somewhere outside you'll need to do something along the lines of:
using (var obj = TheWayYouInitializeYourObject())
{
var commit = obj.BeginTransaction();
// DO WORK
await commit();
}
or
try
{
var commit = obj.BeginTransaction();
// DO WORK
await commit();
}
finally
{
obj.Dispose();
}
Basically, your using
cannot span the gap in which your user works, so they'll have to do it on their own.
It is generally a good idea to make objects that have to work with disposables disposable as well.