0

Here is the code:

using(var context = new FirstAppDemoDbContext())
{
     SQLEmployeeData sqlData = new SQLEmployeeData(context);
     model.Employees = sqlData.GetAll();
}

I know that the using statement will destroy the "context" object after finishing with using block, but I wonder if it will destroy the object instantiated inside the using block (I mean "sqlData"). Does it destroy the "sqlData" object as well?

More generally, Does the using block destroy whatever is defined inside the block (inside bracket)?

Ali
  • 9
  • 2
  • 7
    No, only `context`. – ProgrammingLlama Aug 17 '22 at 09:54
  • Not sure what you mean by "destroy"; it ensures the `Dispose` method is called when `context` is out of scope. Any variables declared within the block are unaffected. – Johnathan Barclay Aug 17 '22 at 09:57
  • 1
    If it was disposing everything inside using, how could you use anything there that should not be disposed? Then `using` was unusable. Also, only the instance used in the `using` is disposed, not everything that this instance is using. The dispose method of this object has to take care of that. – Tim Schmelter Aug 17 '22 at 10:00
  • All variables are scoped to to the block they are declared in and so, will go out of scope when the block is exited. Then, some time later, will be garbage collected. Variables declared in an outer block are unaffected. This is different to being disposed. The using statement/block is used to ensure the disposal of an `IDisposable` implementer. – Jodrell Aug 17 '22 at 10:02
  • 1
    Just add `using`: `using SQLEmployeeData sqlData = new SQLEmployeeData(context);` and `sqlData` will be disposed on leaving its scope – Dmitry Bychenko Aug 17 '22 at 10:04
  • 3
    If it had worked as you supposed, why do you think the language designers would have forced you to pick out one of the variables to put inside the `()` part? Why would they not have given us `using { ... }` as the complete block? – Damien_The_Unbeliever Aug 17 '22 at 10:07
  • @Damien_The_Unbeliever: it's little bit like the [`TransactionScope`](https://stackoverflow.com/questions/542525/transactionscope-vs-transaction-in-linq-to-sql) is implemented. It manages everything that is used in it's scope. So whatever is used there is part of the transaction. But for sure it's easier (and more useful) to implement that instead of a `using` that disposes everything inside. – Tim Schmelter Aug 17 '22 at 10:18
  • If you want to create and dispose multiple objects then use multiple `using` statements. You can have multiple statements before the opening brace of a block or, if you need to interleave other code between them, you can nest multiple `using` blocks. If you don't have to dispose an object then "destroying" it is pretty much meaningless. Other than that, variables declared and objects created inside a `using` block are just like any other variables and objects inside any other block. – John Aug 17 '22 at 10:22
  • Does this answer your question? [Does "using" statement always dispose the object?](https://stackoverflow.com/questions/17357258/does-using-statement-always-dispose-the-object) – JHBonarius Aug 17 '22 at 10:29

3 Answers3

5

No, but...

Any variable that was declared inside the block, i.e. between the {}, will go out of scope once you exit the block (which happens at the same time as the using will dispose of the resource), and when it goes out of scope, the garbage collector might activate to collect the object it used to reference.

Garbage collection

In short, the garbage collector is a system that automatically comes and collects any object that is no longer being referenced. In other words, if everyone has forgotten about it, it can be removed. If the object in question is IDisposable, the garbage collector will be smart enough to call its Dispose method.

This is in sharp contrast to the using method, which will dispose your object even if others are still referencing it.

A second thing to point out is that the garbage collector comes when he wants to. There are ways to force him to come; but generally speaking you won't be managing this, and the .NET runtime will send the garbage collector when it wants to do so.

Let's use a short example here. I'm using an if here, but the same would be true of any scope block (commonly bounded by {})

Person a;

if(true)
{
    Person b = new Person("Bob");
    Person c = new Person("Cindy");
    a = c;
}

// We have now exited the block

When you reach the comment, consider the object that b refers to (which I will call Bob from this point on).

This object is referenced only by the variable b. When we exited the if block, b went out of scope and no longer exists. Therefore, we can say for certain that no one is still referencing Bob. Therefore, when the garbage collector comes, he will collect Bob and dispose of him.

However, since the garbage collector comes whenever he want to; we cannot be certain that he has already come by to collect Bob. Bob may still be in memory, or he may already have been disposed on. In general, we don't care. The runtime will manage that part for us.

Let's consider the object referenced by a and c (which I will call Cindy from this point on).

This object is referenced by two variables: a and c. When we exited the if block, c went out of scope and no longer exists. However, a is still in scope.
Therefore, we can conclude that someone is still referencing Cindy. Therefore, when the garbage collector comes, he will not collect Cindy and dispose of her.

Back to your example

When you hit the end of the using block, several things happen:

  • The runtime explicitly disposes of the object referenced by context
    • Note that the runtime does not care whether there are other variables which have not yet gone out of scope that are referencing this object. It just doesn't care. It was told to dispose, therefore it disposes.
  • Because we exit the block, the sqlData variable goes out of scope.
    • This object is referenced only by the variable sqlData. Therefore, we can say for certain that no one is still referencing this object. Therefore, when the garbage collector comes, he will collect the object and dispose of it.
    • However, we don't know if the garbage collector has already come for this object. Maybe it's still in memory somewhere, maybe it's already been collected.
  • model did not go out of scope as it was declared on a higher level, so the garbage collector will not attempt to collect the object referenced by model.
  • The object returned by sqlData.GetAll() is still being referenced by model.Employees, and therefore the garbage collector will not attempt to collect it.

In short

  • Using statements immediately dispose of the explicitly declared resource (between the using( and ))
  • When you exit a block ({}), any objects that were only being referenced by variables that now went out of scope, are going to be collected by the garbage collector, but not necessarily immediately.
Flater
  • 12,908
  • 4
  • 39
  • 62
  • Strictly, in release mode a variable no longer keeps an object alive if it is provably never dereferenced again. The GC doesn't have to wait until the end of the block. It's possible to create contrived circumstances where e.g. an object can be collected whilst its *constructor* is still running (provided any variable it is going to be assigned to, if any, is never read and provided the remainder of the constructor no longer explicitly or implicitly makes use of the `this` reference) – Damien_The_Unbeliever Aug 17 '22 at 12:10
  • @Damien_The_Unbeliever I opted for a simpler upper boundary to explain the basics, but you are correct that this can be micromanaged further. – Flater Aug 17 '22 at 12:14
0

The using statement does not "destroy" anything that is defined/instantiated within it's block.

Using statements are used to called Dispose on disposable objects when the go out of scope - this is important as Dispose is primarily used for freeing up unmanaged resources.

Whatever is defined/instantiated within a using block will eventually go out of scope and be collected by the garbage collector - when the objects go out of scope will depend on if they were defined within the block or before it / where they are last referenced.

YungDeiza
  • 3,128
  • 1
  • 7
  • 32
0

By looking at the "lowered" code of the compiler output, you can see more clearly exactly what the using statement is doing.

Model model = new Model ();
FirstAppDemoDbContext context = new FirstAppDemoDbContext();
try
{
    SQLEmployeeData sqlData = new SQLEmployeeData(context);
    model.Employees = sqlData.GetAll();
}
finally
{
    if (context != null)
    {
         ((IDisposable)context).Dispose();
    }
}

The using statement simply compiles to a try/finally block that calls dispose on context in the finally block as long as context is not null.

Nothing interacts with sqlData or model inside of the try block. If you need to handle those resources (outside of normal garbage collection), you would need to do so inside the using statement itself.

David L
  • 32,885
  • 8
  • 62
  • 93