8

How to implement the Dispose pattern when my class contains a socket & event?

Should it be something like this?

class MyClass
{
   Socket m_ListenerSocket = new Socket();
   book m_Disposed=false;

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

   private void Dispose(bool isDisposing)
   {
      if (!m_Disposed)
      {
          if (isDisposing)
          {
              if (m_ListenerSocket != null)
              {
                   m_ListenerSocket.Dispose();
                   innerClass.Notify -= Notify;
              }
          }
        //finalized unmanged code here
        m_Disposed = true;
      }
  }

  ~MyClass()
  {
       Dispose(false);
  }
}

I'm confused... is socket class is "managed code c# version of winSock"? so it should be released in case of user called dispose ("isDisposing IS true") what about event handlers?

so at finalized comment section should free only Inptr objects? Thanks.

Mr_Green
  • 40,727
  • 45
  • 159
  • 271
roman
  • 607
  • 2
  • 10
  • 18
  • Looks good to me. System.Net.Sockets.Socket is a managed class with a finalizer. So you do not have to release it from your class' finalizer. The event handler should also be removed so that GC will not find the object on the live object graph. – Panos Rontogiannis Nov 13 '12 at 07:52
  • As I see it, you don't need to implement the full Dispose pattern that is including a finalizer, since Socket is already a managed resource and implements it's own Finalizer. [This closely related](http://stackoverflow.com/questions/898828/c-sharp-finalize-dispose-pattern) question pretty much sums up the Dispose pattern and it's usage. – PHeiberg Nov 13 '12 at 07:53
  • 1
    @PanosRontogiannis and OP - IIRC, just by implementing a Finalizer on a class you will cause the instances of that class to stick around for one extra GC, so I don't think it's good to use finalizers unless needed. – PHeiberg Nov 13 '12 at 07:57
  • @PHeiberg You are right! – Panos Rontogiannis Nov 13 '12 at 08:39
  • i'm just want to be clear. if you have a class that holds a socket. now the program is runnning out of memory and gc happens automatically. in that case as i understand the dispose method will not called. (because you didn't call it) and you left with a leak. this is the reason i'm asking again is the finalizer nessesary? – roman Nov 13 '12 at 11:16

4 Answers4

3

I think there are many ways to deal with disposable objects, regardless if they have events or not.

Is only a wild guess, but if you took a class from the .net framework and this class has a Dispose() method, you can pretty much say that it is managed code, so you are safe just to call the Dispose method instead of creating the destructor by yourself. This is rather obiquitous because as you see in my example below, you can also implement IDisposable interface in your own classes and then dispose your internal objects in a proper way.

Could this be helpful to you?

public class MyClassWithSocket :IDisposable 
{

    Socket myInternalSocket = null;

    public void methodThatUsesSocket()
    {
        using (var mySocket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream , ProtocolType.Tcp))
        {
        //do something with socket 
        //this will be disposed automatically

        }
    }

    public void methodThatUsesInternalSocket() 
    {
        myInternalSocket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
        //do other things
    }

    public static Socket SomethingThatReturnsSocket()
    {

        Socket tempSocket =  new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);

        return tempSocket;
    }


    public void Dispose()
    {
        myInternalSocket.Dispose();
    }
}
Jorge Alvarado
  • 2,664
  • 22
  • 33
  • I know that when possible & class implement dispose we can use the automatic dispose by using the "using statement". but first question is does we count on that that when the .net object has dispose it is managed code? because as i understand.. the socket class is a .net managed implementation of the winsock unmanged code.. & the second question so what it cosiderd to be unmanged code? intptr object? maybe more examples? – roman Nov 13 '12 at 08:01
  • So for your first question: YES, whenever you take a class from the .net framework (that is all libraries starting with System... you can safely just call $Dispose and the Garbage collector will take care of that. For your second question, pretty much whenever you want to call a class from the Win32 API or using reflector to load other types of libraries you should make the cleaning by yourself. Does that solves your question? – Jorge Alvarado Nov 13 '12 at 08:10
  • but if GC occurs when i still using my class that owns a socket.. and my class doesn't have a finalizer.. how the ineer socket resourse should be released? – roman Nov 13 '12 at 09:29
  • for that question, I think PHeiberg also gave a really good reference before: http://stackoverflow.com/questions/898828/c-sharp-finalize-dispose-pattern – Jorge Alvarado Nov 13 '12 at 10:15
  • What I can tell you is this: 1) you are only responsible for your own class and resources that you use within the class, you cannot dispose objects that are not under your direct control 2) you will never be able to tell when GC comes in, but for sure, it won't be called while you're still using your instantiation 3) for good design, if you are using disposable objects, is always good to implement IDisposable and not let things hanging. – Jorge Alvarado Nov 13 '12 at 10:28
2

Since Socket is a managed class, the guidelines for implementing IDisposable states that no Finalizer is needed. In fact, having a finalizer will actually cause the Garbage Collection of the object to be delayed, since it will call the finalizer during the first garbage collection and garbage collect the object the second time garbage collection is run.

Regarding the event you'll probably want to de-register from the event in the Dispose method, since the event subscription will cause innerClass to hold a reference to the instance of MyClass, unless the innerClass object is short lived. See this question for more info on events and Dispose.

I think that the following implementation would be enough for your scenario:

class MyClass : IDisposable
{
   Socket m_listenerSocket = new Socket();

   public void Dispose()
   {
       m_listenerSocket.Dispose();
       innerClass.Notify -= Notify; 
   }
}

The part in your code that you have commented with "finalized unmanged code here" should only release unmanaged resources, such as handles in the form of IntPtr, etc. Since the introduction of SafeHandle in .NET 2.0, you rarely need to do so, since you can wrap your IntPtr in aSafeHandle and then treat it as a managed resource.

Community
  • 1
  • 1
PHeiberg
  • 29,411
  • 6
  • 59
  • 81
  • i got your point regarding events. but i'm just want to be clear. if you have a class that holds a socket. now the program is runnning out of memory and gc happens automatically. in that case as i understand the dispose method will not called. (because you didn't call it) and you left with a leak. this is the reason i'm asking again is the finalizer nessesary? – roman Nov 13 '12 at 10:37
  • If you're holding on to an instance of a class that in it's turn is holding on to a Socket, the socket will remain in memory for until the reference chain is broken. If you don't dispose the Socket, it will hold on to an unmanaged resource until the your reference to it has been released and it can be garbage collected. The Finalizer is not neccessary and should not be used for managed resources. The user of the managed resource should instead call the `Dispose` method when it's done, or have a `using` block. – PHeiberg Nov 13 '12 at 11:16
1

Thou shalt never let anything go unasserted.

In my experience the widely used "soft error" Dispose(disposing) mechanism is ill conceived. I prefer "hard error".

When I write objects that implement Dispose() I usually extend a MyDisposable class which, #if DEBUG does the following:

  1. Its constructor captures the current stack trace and saves it for later. (Note: this is extremely slow, Microsoft only knows why.)
  2. The class contains a bool disposed member initialized to false.
  3. Dispose() asserts that the object has not already been disposed, and then marks the object as disposed.
  4. The destructor of the object (invoked upon finalization) checks whether the object has been disposed, and if not, dumps the stack trace recorded during creation. This allows me to locate the exact spot in my source code which allocated a disposable object but forgot to dispose it.

Also, objects derived from MyDisposable usually assert !disposed as a precondition in every single method, even every single getter.

The above guarantees that:

  1. There is only one way in which an object can be disposed.
  2. Each disposable object will be disposed once and only once.
  3. No method of a disposable object will ever be invoked once the object has been disposed.
  4. If I ever forget to dispose a disposable object, I will find out, and I will know exactly where it was allocated.

It goes without saying that if not #DEBUG then MyDisposable compiles to practically nothing, so as not to hinder performance.

Consequently, I try to avoid (when practical) using classes that implement the "soft error" Dispose(disposing) mechanism without first wrapping them in classes implementing my "hard error" Dispose() mechanism.

Mike Nakis
  • 56,297
  • 11
  • 110
  • 142
0

The existing answers say it already but they are rather verbose. Let me state more clearly that this is all you need:

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

This is not abridged. You can delete everything else.

No need for a finalizer. No need for null tests. You can dispose multiple times safely.

The "dispose pattern" exists for finalizable objects (extremely rare) and for inheritance (rare). Almost always this pattern does not help at all but damages code quality.

Dave R.
  • 7,206
  • 3
  • 30
  • 52
usr
  • 168,620
  • 35
  • 240
  • 369