2

Hi I'm new in this great community and I have my first question. Hope this one is in the right place (and I hope my english is correct):

I'm novice developer and I have to improve a C# Application, so I've found this code and I want to know if this is the right way to do it:

ObjClass obj = new ObjClass();
obj.SomeText = TextBox1.Text;
obj.SomeNumber = Convert.ToInt32(TextBox2.Text);

The definition of ObjClass is the following:

    using System;

namespace SomeObject
{
    public class ObjClass : IDisposable
    {
        public string SomeText { get; set; }
        public int SomeNumber{ get; set; }

        public void Dispose()
        {
            GC.SuppressFinalize(this); 
        }
    }
}

Then after using the object the code to finalize or disposing the objecto is the following:

if(obj.SomeNumber != null)
{
    //doing something else
    obj.Dispose();
}
Ricibob
  • 7,505
  • 5
  • 46
  • 65
  • 3
    possible duplicate of [Implementing IDisposable correctly](http://stackoverflow.com/questions/18336856/implementing-idisposable-correctly) – James Thorpe Feb 18 '15 at 20:30
  • Note that that answer is incorrect, it doesn't implement a finalizer. Not sure why it was upvoted in the first place, it just propagates bad coding practices. – Blindy Feb 18 '15 at 20:35
  • @Blindy True. There may be a better dupe target or canonical answer for this – James Thorpe Feb 18 '15 at 20:37
  • @James probably the best C# IDisposable answer ever: http://stackoverflow.com/questions/538060/proper-use-of-the-idisposable-interface/538238#538238 – Filipe Borges Feb 18 '15 at 20:55
  • what makes the question a possible duplicate of [Proper use of the IDisposable interface](http://stackoverflow.com/questions/538060/proper-use-of-the-idisposable-interface) – Filipe Borges Feb 18 '15 at 20:56
  • Thanks to you all, I'm already reading the other answers to get a better approach for my solution. I guess that for this particular example the `using` block is the best way to this. – Jorge Escamilla Feb 18 '15 at 22:54

3 Answers3

2

If a class is disposable the best way to make sure it gets disposed is to use a using block.

using(var foo = new ObjClass())
{
    // do something
}

This will ensure that the object is disposed even if an exception occurs.

Craig W.
  • 17,838
  • 6
  • 49
  • 82
2

The correct way would be not to write a Dispose function at all. At best you're just tying up the GC, preventing it from freeing your object until it invokes it on the GUI thread (slowing it down) and gets back confirmation that it has run. At worst you write it as bad as you did and end up with potential memory leaks.

Now if you handle native memory or resources directly in your object (and it's rare, you can avoid handling most of them and leave it to .NET), the correct way of writing a finalizer (ie the part you're missing!) is:

public class Base: IDisposable
{
    private bool disposed = false;

    //Implement IDisposable.
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                // Free other state (managed objects).
            }
            // Free your own state (unmanaged objects).
            // Set large fields to null.
            disposed = true;
        }
    }

    // Use C# destructor syntax for finalization code.
    ~Base()
    {
        // Simply call Dispose(false).
        Dispose (false);
    }
}

Where your code simply prevents finalizers from running, this code either calls Dispose(false) in your finalizer (ie when the GC determines that your object is useless and tries to free it) or Dispose(true) when you call Dispose() yourself (and then prevents the GC from calling the finalizer so you don't dispose twice).

As to how you use it, this is the correct way:

using(var obj = new Base())
{
   // do whatever you want
   // obj.Dispose() will automatically be called at the end of scope
}

Which is functionally equivalent to:

try
{ 
   var obj = new Base();  
   // use the object
} 
finally 
{
   // always called, even during exception stack unwinding  
   obj.Dispose();
}

And again, the correct way is not to write a Dispose. Every time you are required to do it, it's a failure of the framework to provide you with the right tools to stay in the managed world. These instances are fewer and fewer nowadays.

Blindy
  • 65,249
  • 10
  • 91
  • 131
0

Welcome to the wonderful world of IDisposable! I see this as 2 questions:

1) Is the implementation of ObjClass correct - does it need to implement IDisposable?
A class should implement IDisposable:
a. Because it hold unmanaged resources. If this applies use the "standard IDispose implementation" (search and you will find). This case is actually quite rare. It doesn't appear to be the case for this class - its only two members are managed.
b. Because the class holds managed objects that implement IDisposable and you want the user of your class to be able to control WHEN the resources those manage objects hold are freed. Note here its not about IF the resources are freed - they always will be freed eventually by the GC - but by offering IDisposable you allow your class user to control when that happens. A good example here is a class that holds a managed Socket object. Socket implements IDisposable which will close the port. By you class implementing IDisposable and disposing the socket in its Dispose method you are allowing your class user to control WHEN the socket gets closed.
Neither of the above a. or b. are the case here with the class as its written so implementing IDisposable here appears wrong.

2) Is the way an instance of ObjClass is used correct?
It is OK to call Dispose explicitely when you're done with an object - there is nothing strictly incorrect about doing that. However the using statement is the prefered way to do this. Importantly (as mentioned in the other answer) a using block includes a behind the scenes a try/catch and a finally to dispose the object - which is important. If you dont use "using" you should have a try catch to dispose the object if there is an exception.

Ricibob
  • 7,505
  • 5
  • 46
  • 65