Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using statement in every function -> convert to class field with proper cleanup?

Basically I have a few functions that look like this:

class MyClass
{
    void foo()
    {
       using (SomeHelper helper = CreateHelper())
       {
           // Do some stuff with the helper
       }
    }

    void bar()
    {
        using (SomeHelper helper = CreateHelper())
        {
           // Do some stuff with the helper
        }
    }
}

Under the assumption I can use the same resource instead of a different one [instance] in every function is it ok practice in regard to cleanup and such to do this?:

class MyClass
{
    SomeHelper helper = CreateHelper();

    // ...foo and bar that now just use the class helper....

    ~MyClass()
    {
      helper.Dispose();
    }
}
like image 644
Joshua Enfield Avatar asked Nov 22 '11 18:11

Joshua Enfield


People also ask

What is using () in C#?

The using statement causes the object itself to go out of scope as soon as Dispose is called. Within the using block, the object is read-only and can't be modified or reassigned. A variable declared with a using declaration is read-only.

What is code cleanup C#?

"Code Cleanup automatically on Save is a new feature integrated into Visual Studio 2022 that can clean up your code file to make sure it is formatted correctly and that your coding style preferences are applied. Some customizable preferences include: format document, sort usings, remove unnecessary usings, and more.

How do I clean my code in VS code?

Right-click on the project or solution name in Solution Explorer, select Analyze and Code Cleanup, and then select Run Code Cleanup.

What is the use of using statement in C# with example?

The using statement is used to set one or more than one resource. These resources are executed and the resource is released. The statement is also used with database operations. The main goal is to manage resources and release all the resources automatically.


2 Answers

No, do not add a destructor (Finalizer).

You can reuse the resource but then your class has to implement IDisposable.

sealed class MyClass : IDisposable
{
    SomeHelper helper = CreateHelper();

    // ...foo and bar that now just use the class helper....

    //~MyClass()
    public void Dispose()    
    {
      helper.Dispose();
    }                         
}

And now you have to use MyClass instances in a using block. It self has become a managed resource .

A destructor is of no use, whenever a MyClass instance is being collected the associated helper object will also be in the same collection. But having a destructor still incurs considerable overhead.

The standard pattern for IDisposable uses a virtual void Dispose(bool disposing) method but when making the class sealed you can use the minimalistic implementation above.

like image 167
Henk Holterman Avatar answered Sep 30 '22 19:09

Henk Holterman


In .NET you don't know when (or whether) finalizer is called at all.

Instead, explicitly indicate that your class is to be disposed of by implementing IDisposable:
(This is exactly what SomeHelper does)

class MyClass : IDisposable
{
    readonly SomeHelper helper = CreateHelper();

    // any method can use helper

    public void Dispose()
    {
       helper.Dispose();
    }
}

using(var myObj = new MyClass()) {
    // at the end, myObj.Dispose() will trigger helper.Dispose()
}

I used readonly to ensure helper doesn't get re-assigned somewhere else in the class, but this really doesn't matter if you're careful.

You must be extra careful to never set it to null, or your Dispose will throw an exception. If the field is protected, you can check for nullity before calling Dispose on it so you know you're playing safe.

like image 35
Dan Abramov Avatar answered Sep 30 '22 20:09

Dan Abramov