I'm designing a fluent API and the usage is somewhat like this:
IUser user = work
.Timeout(TimeSpan.FromSeconds(5))
.WithRepository(c => c.Users)
.Do(r => r.LoadByUsername("matt"))
.Execute();
So, let's say that work
is of type IUnitOfWork
, but the method WithRepository(c => c.Users)
returns an interface called IActionFlow<IUserRepository>
which is IDisposable
.
When I call Execute()
and get the final result, I lose the reference to that IActionFlow<IUserRepository>
instance so I can't dispose it.
What are the disadvantages of having the instance dipose itself on the Execute()
method?
Something like:
public TResult Execute()
{
// ...
Dispose();
return result;
}
The code seems to compile just fine but I'm looking for strange behaviors or bugs that may rise because of this. Is it bad practice at all?
Implement a finalizer to free resources when Dispose is not called. By default, the garbage collector automatically calls an object's finalizer before reclaiming its memory. However, if the Dispose method has been called, it is typically unnecessary for the garbage collector to call the disposed object's finalizer.
The Dispose() methodThe Dispose method performs all object cleanup, so the garbage collector no longer needs to call the objects' Object. Finalize override. Therefore, the call to the SuppressFinalize method prevents the garbage collector from running the finalizer. If the type has no finalizer, the call to GC.
A disposed object is an object that implements IDisposable that has had the Dispose method called. This could be called explicitly or after a using statement completes. If it's happening sporadically, it might be a race condition.
Microsoft recommends that we implement both Dispose and Finalize when working with unmanaged resources. The Finalize implementation would run and the resources would still be released when the object is garbage collected even if a developer neglected to call the Dispose method explicitly.
You can have Using
method like this:
public static TResult Using<TDisposable, TResult>(Func<TDisposable> factory,
Func<TDisposable, TResult> fn) where TDisposable : IDisposable {
using (var disposable = factory()) {
return fn(disposable);
}
}
Then your code would look like this:
var user = Using(() => work.
Timeout(TimeSpan.FromSeconds(5)).
WithRepository(c => c.Users),
repository => repository.Do(r => r.LoadByUsername("matt")).
Execute());
This will allow your API to stay fluent and at the same time you will dispose WithRepository
the same moment Execute
is completed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With