Proper technique for issuing socket / event / loss code using the dispose / finalize pattern

How to implement a Dispose pattern when my class contains a socket and an event?

Should there 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 the socket class a "managed C # version of winSock code"? so it should be released if the user called dispose ("isDisposing IS true") what about event handlers?

so in the completed comment section should only Inptr objects be freed? Thanks.

+8
c # dispose sockets finalize unmanaged
source share
4 answers

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

This is just a wild guess, but if you took a class from a .net structure, and this class has a Dispose () method, you can pretty much say that it is managed code, so you can just call Dispose instead of creating the destructor yourself. This is quite offensive, because, as you see in my example below, you can also implement the IDisposable interface in your own classes, and then properly manage your internal objects.

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(); } } 
+3
source share

Because Socket is a managed class, the IDisposable implementation guide states that Finalizer is not required. In fact, having a finalizer will actually delay the collection of object garbage, since it will call the finalizer during the first garbage collection, and garbage collects the object a second time garbage collection.

Regarding the event, which you probably want to cancel from the event in the Dispose method, since subscribing to the event will cause innerClass to contain a reference to the MyClass instance, if only the innerClass object is short-lived. See this question for more information on events and Dispose.

I think the following implementation will suffice for your scenario:

 class MyClass : IDisposable { Socket m_listenerSocket = new Socket(); public void Dispose() { m_listenerSocket.Dispose(); innerClass.Notify -= Notify; } } 

The part of your code that you commented on with “finalized unchanged code here” should only produce unmanaged resources, such as descriptors in the form of IntPtr , etc. After introducing SafeHandle in .NET 2.0, you rarely have to do this because you can wrap IntPtr in SafeHandle and then treat it as a managed resource.

+2
source share

You can’t let anyone go.

In my experience, the Dispose(disposing) soft error mechanism is widely used. I prefer the “hard mistake”.

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

  • Its constructor captures the current stack trace and saves it later. (Note: this is very slow, Microsoft knows why.)
  • The class contains the bool disposed member, initialized to false .
  • Dispose() claims that the object has not yet been deleted, and then marks the object as located.
  • The object's destructor (called upon completion) checks whether the object has been deleted, and if not, deletes the stack trace recorded at creation time. This allows me to find the exact spot in my source code that allocates a one-time object, but forgot to destroy it.

In addition, objects derived from MyDisposable usually claim !disposed as a prerequisite in every single method, even every single getter.

The above guarantees that:

  • There is only one way that an object can be deleted.
  • Each disposable item will be placed once and only once.
  • When deleting an object, the one-time object method will never be called.
  • If I ever forget to dispose of a disposable item, I will find out, and I know exactly where it was allocated.

It goes without saying that if not #DEBUG , then MyDisposable hardly compiles, so as not to interfere with performance.

Therefore, I try to avoid (when appropriate) the use of classes that implement the Dispose(disposing) soft error mechanism, without first wrapping them in classes that implement the Dispose() hard error mechanism.

+1
source share

Existing answers already talk about this, but they are pretty verbose. Let me state more clearly that this is all you need:

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

This is not shrinking. You can delete everything else.

No finalizer needed. No need for null tests. You can use repeatedly safely.

"Template recycling" exists for finalizable objects (extremely rare) and for inheritance (rarely). Almost always, this template does not help at all, but it damages the quality of the code.

0
source share

All Articles