returning in the middle of a using block
As several others have pointed out in general this is not a problem.
The only case it will cause you issues is if you return in the middle of a using statement and additionally return the in using variable. But then again, this would also cause you issues even if you didn't return and simply kept a reference to a variable.
using ( var x = new Something() ) {
// not a good idea
return x;
}
Just as bad
Something y;
using ( var x = new Something() ) {
y = x;
}
Is it a good approach to call return inside using {} statement?
It's perfectly safe to call return
inside your using
block, since a using block is just a try/finally
block.
In your example above after return true
, the scope will get disposed and the value returned. return false
, and scope.Complete()
will not get called. Dispose
however will be called regardless since it reside inside the finally block.
Your code is essentially the same as this (if that makes it easier to understand):
var scope = new TransactionScope())
try
{
// my core logic
return true; // if condition met else
return false;
scope.Complete();
}
finally
{
if( scope != null)
((IDisposable)scope).Dispose();
}
Please be aware that your transaction will never commit as there's no way to get to scope.Complete()
to commit the transaction.
Return a FuncTask middle of Using block
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.
What happens when 'return' is called from within a 'using' block?
Yes it does. The disposing of the object occurs in a finally block which executes even in the face of a return call. It essentially expands out to the following code
var context = new linqAssignmentsDataContext();
try {
return context.Persons.Where(p => p.LastName.Contans("dahl"));
} finally {
if ( context != null ) {
context.Dispose();
}
}
Return a Disposable object for use in a using block
You've got the right approach, but seem a bit lost as to how it's right.
Consider the code that you (correctly) say can't work:
DBHandle GetDB()
{
using( var db = DatabaseObj.GetHandle() )
{
db.Open();
return db;
}
}
This code is pretty much equivalent to:
DBHandle GetDB()
{
var db = DatabaseObj.GetHandle();
try
{
db.Open();
return db;
}
finally
{
if(db != null)//not included if db is a value-type
((IDisposable)db).Dispose();
}
}
A few things of note here include that the try doesn't happen until after the assignment (the same is true of using
- it doesn't save you from exceptions prior to the assignment in the using
) and that db
is cast to IDisposable
meaning both that it can't compile if that assignment isn't valid, and also that Dispose()
can be either implicitly or explicitly implemented and this will work either way.
Now of course, finally
blocks will execute whether an exception occurs or not. You can't use using
because it's equivalent to a finally
and you want to Dispose()
in your method only if an exception occurs. Hence you take the finally and turn it into a catch:
DBHandle GetDB()
{
var db = DatabaseObj.GetHandle();
try
{
db.Open();
return db;
}
catch
{
if(db != null)
((IDisposable)db).Dispose();
throw;
}
}
This is pretty much the same as you have, except for the addition of a null check (maybe you can rule out the need for it) and that I'm using the bare throw
(it's generally a good idea when you are going to re-throw an exception without altering or examining it. In some cases throwing a new exception is better, in which case you should include the original as the InnerException
property of that new exception, so as to provide further information to someone debugging).
So all in all, you were on the right track. Hopefully I've helped explain why.
Returning IQueryable from within a using block. Need better design
If you want to return IQueryable
you can make your class that contains the GetPhoneDirectory
disposable, make the PhoneBookDataContext
a field, and dispose it in your dispose method.
You will then put the onus on the caller to dispose his instance of your class.
E.g.
public class MyClass : IDisposable
{
PhoneBookDataContext db;
public MyClass()
{
db = new PhoneBookDataContext();
}
public IQueryable<PhoneNumber> GetPhoneDirectory()
{
return db.PhoneNumbers.Where(d => d.Site == _site);
}
public void Dispose()
{
if (db != null)
{
db.Dispose();
db = null;
}
}
}
// Caller
using(var myClass = new MyClass())
{
var queryable = myClass.GetPhoneDirectory();
...
}
In Python, if I return inside a with block, will the file still close?
Yes, it acts like the finally
block after a try
block, i.e. it always executes (unless the python process terminates in an unusual way of course).
It is also mentioned in one of the examples of PEP-343 which is the specification for the with
statement:
with locked(myLock):
# Code here executes with myLock held. The lock is
# guaranteed to be released when the block is left (even
# if via return or by an uncaught exception).
Something worth mentioning is however, that you cannot easily catch exceptions thrown by the open()
call without putting the whole with
block inside a try..except
block which is usually not what one wants.
Best practice regarding returning from using blocks
I prefer the first example. Fewer variables, fewer lines of code, easier to follow, easier to maintain...
public int Foo()
{
using(..)
{
return bar;
}
}
Related Topics
Mvcbuildviews Not Working Correctly
Method Overloading VS Optional Parameter in C# 4.0
How to Create an Expression Tree to Represent 'String.Contains("Term")' in C#
Can Bindings Create Memory Leaks in Wpf
Variables Within App.Config/Web.Config
How to Pass a Username/Password in the Header to a Soap Wcf Service
Suppress Warning Cs1998: This Async Method Lacks 'Await'
What's the Best Way to Calculate the Size of a Directory in .Net
How to Replace Part of String by Position
ASP.NET Identity Get All Roles of Logged in User
Return JSON with Error Status Code MVC
Automatic Native and Managed Dlls Extracting from Nuget Package
I Need a Fast Runtime Expression Parser
Does a Locked Object Stay Locked If an Exception Occurs Inside It