-3
using(var myDisposable = new MyDisposable)
{
    //Do stuff.
}

is great and all. But if what you wanted was:

using(var myDisposable = new MyDisposable)
{
    var myAnswer = CalculateMyAnswer(myDisposable);
}

and you wanted to use myAnswer later, then you have to declare myAnswer outside the block, and it's starting to get a bit faffy. :(

Is there any way to declare a using block, but have it not encapsulate scope, so that variables declared inside that block are still visible outside it?


So far my best solution is to just dispose my variable manually:

var myDisposable = new MyDisposable
    var myAnswer = CalculateMyAnswer(myDisposable);
myDisposable.Dispose();

but that loses a lot of what I like about using.

Are there any alternatives?

Brondahl
  • 7,402
  • 5
  • 45
  • 74
  • 8
    What's "faffy" about declaring a variable in the scope that you need it? It seems that any hacks to get around scope would be even faffier. – David May 08 '19 at 23:12
  • 1
    A method that `return CalculateMyAnswer(myDisposable);`? – Jimi May 08 '19 at 23:12
  • Your second solution should probably use `try...finally`, which also creates a code block :( Unfortunately we have to live with defining the variables up top, which is sort of a chore if you're using to using `var` for everything. The other option is just to delay the dispose until the end of the method, so everything is in the code block, including whatever code needs to access `myAnswer`. – John Wu May 08 '19 at 23:24
  • 3
    The using block is incredibly important because it guarantees cleanup. Prioritize program integrity. If that means the variable is declared outside of the using block, so be it. – Chris Rollins May 08 '19 at 23:31
  • 2
    The using block will have less printable character than any other solution you will come up with, its common, people understand it, you can use the async and await pattern inside it meaning you don't need 2 different versions... shortening this sort of thing is basically a waste of time – TheGeneral May 09 '19 at 03:25

2 Answers2

2

You could add some sugar to it to get rid of the using block in your code with this method:

public static class Disposable
{
    public static T Using<R, T>(Func<R> factory, Func<R, T> projection) where R : IDisposable
    {
        using (var r = factory())
        {
            return projection(r);
        }
    }
}

Then you'd just use it like this:

var myAnswer = Disposable.Using(() => new MyDisposable(), m => CalculateMyAnswer(m));
Enigmativity
  • 113,464
  • 11
  • 89
  • 172
  • This solution is simply encapsulating the `Using block` part in a separate generic method and returning the result back to be utilized further, though OP needs to make sure that result has no dependency on disposable type R, which would be disposed post value return – Mrinal Kamboj May 09 '19 at 04:59
  • @MrinalKamboj - Yes, that's entirely true. Calling `Disposable.Using(() => new MyDisposable(), m => m);` would be a bit of a disaster. – Enigmativity May 09 '19 at 05:02
0

A using statement defines a block. If you want a variable to be accessible outside it you need to define it outside of that block, but you can assign to it in the block:

string myAnswer = null;
using(var myDisposable = new MyDisposable)
{
    myAnswer = CalculateMyAnswer(myDisposable);
}
Mureinik
  • 297,002
  • 52
  • 306
  • 350
  • Side note: `var myAnswer = null;` is just a bad idea :) … The need to explicitly define type on that line is likely what OP called "fluff" – Alexei Levenkov May 08 '19 at 23:33
  • 2
    @AlexeiLevenkov - It's not just a bad idea - it's a compiler error: `CS0815 Cannot assign to an implicitly-typed variable`. – Enigmativity May 09 '19 at 00:42