Why is it always necessary to implement IDisposable for an object with an IDisposable member?

From what I can say, it is a generally accepted rule that if you have a class A that has a member m that is IDisposable, A must implement IDisposable and it must call m.Dispose () inside it.

I can not find an acceptable reason why this is so.

I understand the rule that if you have unmanaged resources, you must provide a finalizer along with IDisposable so that if the user does not explicitly call Dispose, the finalizer will still be cleared during the GC.

However, with this rule, it seems you do not need to have a rule in which this question is. For instance...

If I have a class:

class MyImage{ private Image _img; ... } 

The conventions state that I should have MyImage : IDisposable . But if Image followed the conventions and implemented the finalizer, and I don't care about the timely release of resources, what's the point?

UPDATE

Found a good discussion of what I was trying to find in here .

+4
source share
7 answers

But if the image was consistent with the conventions and implemented by the finalizer, and I don’t care about the timely release of resources, what point?

Then there is nobody if you don’t care about the timely release, and you can make sure that the one-time object is written correctly (in truth, I never make such an assumption, even with the MS code. To know when something accidentally slips). The fact is that you should take care, because you never know when this will cause a problem. Consider connecting to an open database. Leaving it hanging means that it is not replaced in the pool. You may end up if you have multiple requests for one.

Nothing is said that you need to do this if you do not care. Think of it like freeing variables in an unmanaged program. This is not necessary for you, but it is very desirable. If, for any other reason, the person who has inherited from the program should not be surprised why he did not take care, then try to clean it.

+6
source

But if the image fulfilled the agreement and implemented the finalizer, and I do not care about the timely release of resources, what is the point?

You have completely missed the Dispose item. This is not about your convenience. This concerns the convenience of other components that may want to use these unmanaged resources. If you cannot guarantee that no other code in the system cares about the timely release of resources, and the user does not care about the timely release of resources, you should release your resources as soon as possible. This is a polite matter.

In the classic

The garbage collector has no reason to know that he needs to run finalizers faster to quickly release these handles; why? His task is to manage memory. Your task is to control the pens, so you need to do this work.

+22
source

Firstly, there is no guarantee that the object will be cleared by the finalizer thread - think about the case when the class refers to the sql connection. If you are not sure that it is disposed of immediately, you will have an open connection for an unknown period of time and you will not be able to reuse it.

Secondly, finalization is not a cheap process - you need to be sure that if your objects are disposed of properly, you call GC.SuppressFinalize (this) to prevent completion.

Expanding in the “not cheap” aspect, the finalizer stream is a high priority stream. This will require resources from your main application if you pay too much attention to it.

Edit: Well, here is Chris Brammy's blog post about Finalizing, including why it is expensive. (I knew I would read loads about it somewhere)

+2
source

If you do not care about the timely release of resources, then in reality there is no point. If you can be sure that the code is only for your consumption, and you have a lot of free memory / resources, why not let the GC change it when it wants. OTOH, if someone else uses your code and creates many instances (e.g. MyImage ), it will be quite difficult to control the use of memory / resources if it does not have it nicely.

+1
source

Many classes require that Dispose be called to ensure correctness. If some C # code uses an iterator with a finally block, for example, the code in this block will not be run if the counter is created with this iterator and will not be deleted. Although there are a few cases where it would be impractical for objects to be cleaned without finalizers, for the most part code that relies on finalizers to work properly or to avoid memory leaks is bad code.

If your code acquires ownership of the IDisposable object, then if no object is closed or your code creates the object by calling the constructor (unlike the factory method), you cannot find out what the real type of the object is, and whether it is possible safe to leave. Microsoft may have initially assumed that it’s safe to abandon any type of object, but this is unrealistic, and the belief that it would be safe to abandon any type of object is futile. If an object subscribes to events, to ensure safe rejection, it is either necessary to add a level of weak indirectness to all events, or a level of (non-weak) access to all other accesses. In many cases, it is better to require the caller to delete the object correctly than to add significant overhead and complexity, allowing you to refuse.

We also note, by the way, that even when objects try to satisfy a failure, it can still be very expensive. Create a Microsoft.VisualBasic.Collection (or whatever it's called there), add a few objects, and create and destroy a million enumerators. No problem - it is very fast. Now create and leave a million enthusiasts. A big holiday of delay, if you do not hit GC every few thousand enumerators. The Collection object is written to resolve a failure, but this does not mean that it does not have significant costs.

+1
source

If the object you are using implements IDisposable, it tells you that it has something important to do when you are done with it. This important thing can be to free up unmanaged resources or to unhook events so that they do not handle events after you think that you have ended with them, etc. Etc. Without calling Dispose, you say that you know better about how this object works than the original author. In some tiny cases, this may be true if you yourself created the IDisposable class or if you know a bug or performance problem associated with calling Dispose. In general, it is very unlikely that ignoring a class that requires you to destroy it when you are done is a good idea.

Speaking of finalizers - as already mentioned, they have a cost that can be avoided by deleting the object (if it uses SuppressFinalize). Not only the costs of starting the finalizer itself, and not just waiting until this finalizer is executed before the GC can assemble the object. An object with a finalizer survives in a collection in which it is identified as unused and needs to be completed. So it will rise (if it is not already in gene 2). This leads to several effects:

  • The next higher generation will be assembled less frequently, so after starting the finalizer, you can wait a long time until the GC approaches this generation and waves your object away. Therefore, it may take a lot longer to free memory.
  • This adds unnecessary pressure to the collection to which the object is moving. If it moves from gen 0 to gen 1, then now gen 1 will fill up earlier than necessary.
  • This can lead to more frequent garbage collection in higher generations, which is another performance hit.
  • If the finalizer of the object is not completed by the time the GC approaches a higher generation, the object may be advanced again. Therefore, in a bad case, you can cause the object to be upgraded from gen 0 to 2 for no good reason.

Obviously, if you do this on only one object, it is unlikely to cost you anything noticeable. If you do this as a normal practice, because you find the Dispose call on the objects you are using is tedious, then this can lead to all of the above problems.

Disposal is like a lock on the front door. This is probably for some reason, and if you leave the building, you should probably lock the door. If it would be nice to lock it, there would be no lock.

+1
source

Even if you do not care in this particular case, you should still follow the standard, because in some cases you will take care. It’s much easier to set a standard and follow it always, based on specific recommendations, than on a standard that you sometimes ignore. This is especially true as your team grows and your product ages.

0
source

Source: https://habr.com/ru/post/891174/


All Articles