126

Returning a method value from inside a using statement that gets a DataContext seems to always work fine, like this:

public static Transaction GetMostRecentTransaction(int singleId)
{
    using (var db = new DataClasses1DataContext())
    {
        var transaction = (from t in db.Transactions
                              orderby t.WhenCreated descending
                              where t.Id == singleId
                              select t).SingleOrDefault();
        return transaction;
    }
}

But I always feel like I should be closing something before I break out of the using brackets, e.g. by defining transaction before the using statement, get it's value inside the brackets, and then returning after the brackets.

Would defining and returning the variable outside the using brackets be better practice or conserve resources in any way?

Edward Tanguay
  • 189,012
  • 314
  • 712
  • 1,047
  • 1
    It might be interesting to look at the general IL for variants of this. I suspect that there would be little difference in the generated IL. I normally wouldnt even bother declaring the var transaction - just return the result of the expression. – Jonesie Mar 03 '10 at 09:09

5 Answers5

166

No, I think it's clearer this way. Don't worry, Dispose will still be called "on the way out" - and only after the return value is fully evaluated. If an exception is thrown at any point (including evaluating the return value) Dispose will still be called too.

While you certainly could take the longer route, it's two extra lines that just add cruft and extra context to keep track of (mentally). In fact, you don't really need the extra local variable - although it can be handy in terms of debugging. You could just have:

public static Transaction GetMostRecentTransaction(int singleId)
{
    using (var db = new DataClasses1DataContext())
    {
        return (from t in db.Transactions
                orderby t.WhenCreated descending
                where t.Id == singleId
                select t).SingleOrDefault();
    }
}

Indeed, I might even be tempted to use dot notation, and put the Where condition within the SingleOrDefault:

public static Transaction GetMostRecentTransaction(int singleId)
{
    using (var db = new DataClasses1DataContext())
    {
        return db.Transactions.OrderByDescending(t => t.WhenCreated)
                              .SingleOrDefault(t => t.Id == singleId);
    }
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 2
    Sine it's you @jon, is it still safe if an exception gets thrown inside the using block? – Dave Archer Mar 03 '10 at 09:08
  • 7
    yes. using is simply syntactic sugar for a try/finally construct – Mitch Wheat Mar 03 '10 at 09:09
  • @David: As Mitch says, it's fine - I've updated the answer to make that clearer :) – Jon Skeet Mar 03 '10 at 09:11
  • 2
    Why use OrderByDescending in combination with SingleOrDefault? – erikkallen Mar 04 '10 at 13:18
  • 2
    @erikkallen: LINQ doesn't have a "MaxBy", unfortunately - so you can't get the row with the maximal value. For LINQ to Objects you can write your own fairly easily, but I'm not sure of a better way of doing it in this case. What would you suggest instead? – Jon Skeet Mar 04 '10 at 13:51
  • @JonSkeet wouldn't it be better (performance wise) to return the value after finalize in cases where the returning value can be materialized so that all using statements don't keep resources for the life time of the materialized result? (e.g. returning decompressed Zlib file contents after using different streams to read and decompress a Zlib file) – Menol May 03 '17 at 10:57
  • @Menol: How would the `using` statements do that? I don't understand your point, I'm afraid. (And nothing's being finalized here... it's being disposed. That's not the same thing.) – Jon Skeet May 03 '17 at 11:02
  • @JonSkeet sorry I meant calling the finally block. Im currently writing a method that reads a zlib file, decompresses it and returns plain text. The example on MSDN uses several nested using statements and the plain text can be materialized in the innermost using block. Wouldn't it be better if I return the plain text after coming out of usings than return it from inside using statements? wouldn't returning from inside usings cause delay in disposing resources I dont need anymore? – Menol May 03 '17 at 11:15
  • @Menol: Why would it delay anything? It sounds like you should probably ask a new question with details. – Jon Skeet May 03 '17 at 12:57
  • @JonSkeet Actually thoroughly reading your answer, MSDN article on using and a quick LinqPad play around helped me to understand what I was confused about. The using will call dispose when the method returns unless the resource it's linked to is still open. I need to read more on how memory allocation works when a method returns a variable. Thanks for your time. – Menol May 04 '17 at 08:19
33

Have a look at this

Understanding the 'using' statement in C#

The CLR converts your code into MSIL. And the using statement gets translated into a try and finally block. This is how the using statement is represented in IL. A using statement is translated into three parts: acquisition, usage, and disposal. The resource is first acquired, then the usage is enclosed in a try statement with a finally clause. The object then gets disposed in the finally clause.

Adriaan Stander
  • 162,879
  • 31
  • 289
  • 284
6

There are no side effects of returning from inside a using() statement.

Whether it makes the most readable code is another discussion.

Mitch Wheat
  • 295,962
  • 43
  • 465
  • 541
0

I think, it's all the same. There's nothing bad in the code. The .NET framework wouldn't care where the object is created. The thing that matters is whether it is referenced or not.

Kerido
  • 2,930
  • 2
  • 21
  • 34
-1

Yes, there can be a side effect. For example, if you use the same technique in ASP.NET MVC Action method, you will get the following error: "The ObjectContext instance has been disposed and can no longer be used for operations that require a connection"

public ActionResult GetMostRecentTransaction(int singleId)
{
    using (var db = new DataClasses1DataContext())
    {
        var transaction = (from t in db.Transactions
                              orderby t.WhenCreated descending
                              where t.Id == singleId
                              select t).SingleOrDefault();
        return PartialView("_transactionPartial", transaction);
    }
}
Alexandre
  • 1,132
  • 1
  • 10
  • 21
usefulBee
  • 9,250
  • 10
  • 51
  • 89
  • 2
    if you define transaction outside of using statement, you will got the same error. using keyword is unrelated in this case. – Costa Oct 05 '15 at 06:12