2

So i am currently disposing many objects when i close my form. Even though it probably disposes it automatically. But still i prefer to follow the "rules" in disposing, hopefully it will stick and help prevent mistakes.

So here is how i currently dispose, which works.

        if (connect == true)
        {
            Waloop.Dispose();
            connect = false;
            UninitializeCall();
            DropCall();

        }
        if (KeySend.Checked || KeyReceive.Checked)
        {
            m_mouseListener.Dispose();
            k_listener.Dispose();

        }
        if (NAudio.Wave.AsioOut.isSupported())
        {
            Aut.Dispose();
        }

        if (Wasout != null)
        {
            Wasout.Dispose();
        }
        if (SendStream != null)
        {
            SendStream.Dispose();
        }

So basically, the first is if a bool is true, meaning if it isn´t those can be ignore, as they haven´t been made i think.

The others are just ways for me to dispose if it´s there. but it´s not a very good way, i would like to have it in 1 big function, meaning.

Dispose if it´s NOT disposed. or something. I know that many of them has the "isdisposed" bool, so it should be possible if i can check every object, and dispose if it´s false.

Zerowalker
  • 761
  • 2
  • 8
  • 27
  • Do you mean that the entire application closes by `when i close my form` ? If so, easy - do nothing. – asawyer Aug 15 '13 at 13:46
  • 1
    @asawyer: That's easy until 6 months from now when he decides that the form shouldn't be his main form, and all of a sudden he's leaking handles. – Jim Mischel Aug 15 '13 at 13:48
  • Yes, and as Jim says, which is why i want to be prepared:) – Zerowalker Aug 15 '13 at 13:49
  • @JimMischel You have to know where to focus your resources. If that's a strong possibility, sure. If not, move on to something else. You have to strike a balance somewhere. – asawyer Aug 15 '13 at 13:49
  • 1
    Don't write senseless code. Find out whether an object is disposable from the documentation and whether it is already getting disposed, no point in guessing at it. If this is a form and the object is not a control or component then high odds that you'll have to dispose it yourself. – Hans Passant Aug 15 '13 at 13:54
  • In addition to what Hans said.. it is so quick to just "Go to definition" in Visual Studio to find what an object implements.. there really is no excuse! – Simon Whitehead Aug 15 '13 at 13:59
  • I check which objects can be dispose and which not. But i am just asking for a way to dispose of them easier when i build them up. As some of them can´t be disposed in using. Or well, they Can, but it will be a performance hit. – Zerowalker Aug 15 '13 at 14:20

4 Answers4

5

How about a helper method which takes objects which implement IDisposable as params?

void DisposeAll(params IDisposable[] disposables)
{
  foreach (IDisposable id in disposables)
  {
    if (id != null) id.Dispose();
  }
}

When you want to dispose multiple objects, call the method with whatever objects you want to dispose.

this.DisposeAll(Wasout, SendStream, m_mouseListener, k_listener);

If you want to avoid calling them explicity, then store them all in a List<>:

private List<IDisposable> _disposables;

void DisposeAll() {
  foreach(IDisposable id in _disposables) {
    if(id != null) id.Dispose();
  }
}
CodingIntrigue
  • 75,930
  • 30
  • 170
  • 176
2

You can implement a Disposer class, that will do the work for you, along these lines:

public class Disposer
{
   private List<IDisposable> disposables = new List<IDisposable>();

   public void Register(IDisposable item)
   {
      disposables.Add(item);
   }

   public void Unregister(IDisposable item)
   {
      disposables.Remove(item);
   }

   public void DisposeAll()
   {
      foreach (IDisposable item in disposables)
      {
        item.Dispose();
      }
      disposables.Clear();
   }
}

Then, instead of the ugly code in your main class, you can have something like:

public class Main
{
   //member field
   private Disposer m_disposer;

   //constructor
   public Main()
   {
       ....
       m_disposer = new Disposer();
       //register any available disposables
       disposer.Register(m_mouseListener);
       disposer.Register(k_listener);
   }

   ...

   public bool Connect()
   {
       ...
       if (isConnected)
       {
           Waloop = ...
           Wasout = ...
           // register additional disposables as they are created
           disposer.Register(Waloop);
           disposer.Register(Wasout);
       }
   }

   ...

   public void Close()
   {
     //disposal
     disposer.DisposeAll();
   }
}
SWeko
  • 30,434
  • 10
  • 71
  • 106
  • But, then i have to register everything iw ant to dispose, to the disposer when it´s created? Though, then again, this will look cleaner. A + for that, will give it a try. – Zerowalker Aug 15 '13 at 14:10
  • @user2587718: not necessarily. You can just have the disposer as a member variable, and register and unregister stuff as needed. – SWeko Aug 15 '13 at 14:12
  • Not sure how to do that, i have added it in private disposer blabla. and am now registering everything like you have done. – Zerowalker Aug 15 '13 at 14:16
  • Okay it doesn´t seem to work, i get Object reference not set to an instance of an object, maybe cause it doesn´t have access to the variables. Tried changing them to public, didn´t help though – Zerowalker Aug 15 '13 at 14:23
  • @user2587718 added a more complete example – SWeko Aug 15 '13 at 14:26
  • I see, but i will still get the Object reference error. not sure why. – Zerowalker Aug 15 '13 at 14:29
  • 2
    If you don't mind using a threadstatic variable, you can define a `T RegisterDisposable(T it) where T:IDisposable` function and use it within object initializers (e.g. `var MyBrush = RegisterDisposable(new SolidBrush());`). Threadstatic variables are icky, but the above approach makes it easy to ensure that variables get initialized and cleaned up. VB.NET allows one to eliminate the threadstatic variable, but I don't know how to do so in C#. – supercat Aug 15 '13 at 15:58
1

I suggest you use the using statement. So with your code, it would look something like this:

  using (WaloopClass Waloop = new WaloopClass())
  {
        // Some other code here I know nothing about.

        connect = false; // Testing the current value of connect is redundant.
        UninitializeCall();
        DropCall();
  }

Note there is now no need to explicitly Dispose Waloop, as it happens automatically at the end of the using statement.

This will help to structure your code, and makes the scope of the Waloop much clearer.

Community
  • 1
  • 1
Polyfun
  • 9,479
  • 4
  • 31
  • 39
1

I am going to suppose that the only problem you’re trying to solve is how to write the following in a nicer way:

if (Wasout != null)
    Wasout.Dispose();
if (SendStream != null)
    SendStream.Dispose();

This is a lot of logic already implemented by the using keyword. using checks that the variable is not null before calling Dispose() for you. Also, using guarantees that thrown exceptions (perhap by Wasout.Dispose()) will not interrupt the attempts to call Dispose() on the other listed objects (such as SendStream). It seems that using was intended to allow management of resources based on scoping rules: using using as an alternative way to write o.Dispose() may be considered an abuse of the language. However, the benefits of using’s behavior and the concision it enables are quite valuable. Thus, I recommend to replace such mass statically-written batches of the “if (o != null) o.Dispose()” with an “empty” using:

using (
    IDisposable _Wasout = Wasout,
    _SendStream = SendStream)
{}

Note that the order that Dispose() is called in is in reverse of how objects are listed in the using block. This follows the pattern of cleaning up objects in reverse of their instantiation order. (The idea is that an object instantiated later may refer to an object instantiated earlier. E.g., if you are using a ladder to climb a house, you might want to keep the ladder around so that you can climb back down before putting it away—the ladder gets instantiated first and cleaned up last. Uhm, analogies… but, basically, the above is shorthand for nested using. And the unlike objects can be smashed into the same using block by writing the using in terms of IDisposable.)

dotnetfiddle of using managing exceptions.

Community
  • 1
  • 1
binki
  • 7,754
  • 5
  • 64
  • 110