The using statement just ensures that Dispose() gets called if an exception is thrown.
This:
using (var foo = new DisposableThing())
{
foo.DoSomething();
}
Is equivalent to:
var foo = new DisposableThing();
try
{
foo.DoSomething();
}
finally
{
foo.Dispose();
}
If you already have a try-catch, just tag a finally at the end and avoid the using statement alltogether.
var scope = new TransactionScope();
try
{
DataBaseStuff();
scope.Complete();
}
catch (Exception ex)
{
LogError(ex);
}
finally
{
scope.Dispose();
}
The using statement isn't some brain-dead best practice; it is syntactic sugar allowing you to clearly define the scope of the disposable resource and have the compiler fill in the finally { foo.Dispose(); } code for you. It's a shortcut, not a law.
Another option is to use an inline using statement:
using var scope = new TransactionScope();
try
{
// do database stuff
scope.Complete();
}
catch (Exception ex)
{
// log exception
}
Another idea:
using (var scope = new TransactionScope())
try
{
//
}
catch (Exception ex)
{
//
}
Smoosh the using statement above the try with no curly braces. This takes advantage of the fact curly braces for the using statement are optional, and act like an if statement with no braces; the next line of code is implicitly part of the block, and since the try-catch is its own block, the compiler puts them all together without the need for additional braces or indentation. The disadvantage here is that it becomes less obvious what is in scope for the using statement. This code construct isn't used often, so it might violate the Principal of Least Astonishment as well.
The inline version of the using statement just calls Dispose() at the end of the method, essentially. I tend to favor the variation that avoids unnecessary levels of indentation, and using a finally block or inline using statements accomplish that. Inline using statements are a little more idiot-proof (you don't need to remember to call Dispose()) but this language feature might not be available if you are working in .NET Framework 4.x or .NET Standard 2.0. For those older framework versions, I would just use a finally block and call Dispose() on the object.