-1

From the MSDN article for implementing Finalize;

You should override Finalize for a class that uses unmanaged resources such as file handles or database connections that must be released when the managed object that uses them is discarded during garbage collection.

From the MSDN article for implementing IDisposible.Dispose;

Use this method to close or release unmanaged resources such as files, streams, and handles held by an instance of the class that implements this interface. By convention, this method is used for all tasks associated with freeing resources held by an object, or preparing an object for reuse.

Which, even in the context of each (thorough) article, seems to be a pretty ambiguous definition.

Where I really lose the purpose of Finalize though, is here;

Because garbage collection is non-deterministic, you do not know precisely when the garbage collector performs finalization. To release resources immediately, you can also choose to implement the dispose pattern and the IDisposable interface. The IDisposable.Dispose implementation can be called by consumers of your class to free unmanaged resources, and you can use the Finalize method to free unmanaged resources in the event that the Dispose method is not called.

Am I supposed to implement both, and force a finalize myself in the event that the consuming application forgets to dispose my object?

Dealing so closely with the GC is new to me...and I want to make sure I drop my resources properly. However, I don't fully understand why both of these exist, or when to use each one.

  • The first quote says "You should override Finalize for a class that uses **unmanaged** resources". So if you don't have any unmanaged resources, you don't override Finalize. – rory.ap Jun 29 '17 at 15:20
  • If the consuming application forgets to dispose your resources, It is their problem. The GC collection might happen immediately or maybe 5 mins later. The goal of Dispose being run on the same thread is to release the resource (let's say a file handle) as soon as possible so that someone else can use it. – Zein Makki Jun 29 '17 at 15:20
  • @user3185569 The GC doesn't take care of unmanaged resources. That's true *by definition*. The *definition* of an unmanaged resource is a resource not managed by the GC. – Servy Jun 29 '17 at 15:21
  • Typically you override the finalizer so that it calls Dispose. The default template for implementing Dispose illustrates this, as well as providing information into the method as to whether the finalizer or user code triggered the dispose method. Also, the Dispose method is deterministic, whereas you never know when the finalizer is going to get called... –  Jun 29 '17 at 15:21
  • What unmanaged resources do you actually have that you need to deal with? – Servy Jun 29 '17 at 15:23
  • @Andrei well, the `IDisposable` pattern includes implementing a finalizer so I'm not sure how you are supposed to "forget" about it. – InBetween Jun 29 '17 at 15:28
  • @InBetween The disposable pattern including implementing a finalizer *when it's appropriate to do so*, which is, for all intents and purposes, never. – Servy Jun 29 '17 at 15:30
  • @Servy interesting. So what happens if a disposable object holding unmanaged resources is GCed without being previously disposed? Does the OS clean up the leaked resources eventually or will they pile up until the application terminates? – InBetween Jun 29 '17 at 15:33
  • @InBetween That will depend radically on the nature of the unmanaged resource. If it's memory that was allocated, it was probably allocated to the process, so it'll go away when the process terminates. If it was some custom resource that isn't tied to a particular process, it might never be cleaned up, ever. You can't really say much of *anything* about unmanaged resources in general, because they can be just about anything. – Servy Jun 29 '17 at 15:38
  • @Servy yes I understand this, but if the redources are allocated by the process and they're not freed, you have a potential memory issue that can crash your application. Implementing the finalizer can help avoid this issue. Of course a case can be made that you are hiding a bug in the code because you should be disposing the object in the first place. I'm always unsure which is the best option, that's why I'm asking. – InBetween Jun 29 '17 at 15:41
  • @InBetween In the case of something like memory allocated for the process, you simply don't need to write the wrapper over that unmanaged resource, because .NET has already written that wrapper. You only need to write objects that compose an `IDisposable`. You'd only need a finalizer for some sort of unmanaged resource that .NET doesn't already have a wrapper for. – Servy Jun 29 '17 at 15:48

2 Answers2

0

Implement both using the Dispose pattern. Visual Studio will even put in the scaffolding for you. Dispose allows you to divest scarce resources as soon as you have finished with them. Finalizer allows you to dispose of them if for some reason the consumer forgets to call your Dispose method but their class instance is allowed to go out of scope.

PhillipH
  • 6,182
  • 1
  • 15
  • 25
  • It's almost always wrong for just about anyone to ever implement a finalizer. If you're implementing a finalizer for any type, you almost certainly shouldn't be. – Servy Jun 29 '17 at 15:22
  • Sorry that's completely incorrect. The MSDN .net Platform Guide Framework Design Guidelines tell you how to implement the Dipose pattern here https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/dispose-pattern. If you implement Dispose you should always implement Finalize. If you implement Finalize without dispose, or dispose without Finalize - then you are doing something wrong. – PhillipH Jun 29 '17 at 15:32
  • You should read your own link, because it contradicts your own statements. It describes when it is, and isn't, appropriate to have a finalizer, and when it is, and isn't, appropriate to implement `IDisposable`. The situations in which it's appropriate to implement `IDisposable` are likely to come up every so often for most C# developers. The situations in which it's appropriate to add a finalizer just about never come up for any C# developer. If you're writing a finalizer, odds are pretty high you're doing something wrong. – Servy Jun 29 '17 at 15:36
  • If you mean "dont exlcusively finalize" then yes, but if you implement the Dispose pattern, you always implement a finalizer - even VS.net scaffolds it that way. You can always supresses the finalizer in Dispose (best practise anyway). If you implement Dispose without a Finalizer you are not protecting your non-CLR assets very well - consider a simple Bitmap object embeded in your class; you can Dispose it when your class gets Disposed, but if your caller forgets the Dispose()/using{} your Finalizer is all that stands in the way of a later GDI fault. – PhillipH Jun 29 '17 at 19:48
  • No, that's just all wrong. You don't dispose of a `Bitmap` in a finalizer. You don't ever touch any other managed objects in a finzalizer. You only ever use a finalizer to interact **direct** (and not indirectly through other managed objects) with an unmanaged resource. It's *unsafe* to access another managed object in the finalizer. In your example, since the object has unmanaged resources to clean up directly, it has nothing to do in its finalizer, it should simply dispose of the bitmap in `Dispose` and have no finalizer. – Servy Jun 29 '17 at 19:57
  • And of course that's the common example. You'll *very* rarely have an actual unmanaged resource to clean up directly, you will, often enough, have some other `IDisposable` object that you compose. When your object has other `IDisposable` objects it should implement `IDisposable,` dispose of them when it's disposed, and *not have a finalizer at all*. – Servy Jun 29 '17 at 19:59
  • Without making this into a endless discussion; I agree with you until you say "dispose of them when it's disposed, and not have a finalizer at all" - the point of the Dispose Pattern is to make sure that, even if your Dispose is not called, you don't leak unmanaged resources, even if they are Composed IDisposable themselves. You shouldn't need to call the disposal routines from your Finalizer, but it exists to make sure your code is safe and doesn't leak resources. – PhillipH Jun 30 '17 at 11:25
  • No, not only do you not need to dispose of managed objects in your finalizer, but **it's unsafe to call another object's `Dispose` method from a finalizer**. It's *inappropriate* to do so, *ever*. You're quite likely to *break* the code by doing so. A finalizer is there to dispose of directly composed unmanaged resources, not managed objects that themselves have unmanaged resources. If you are composing a managed object that itself is disposable then it is *its* responsibility to dispose of any directly composed unmanaged resources. – Servy Jun 30 '17 at 13:11
-1

Just implement IDisposable pattern like that if you have unmanaged resources:

public class ApiClient : IDisposable 
{  
    private readonly HttpClient http = new HttpClient();

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

    protected virtual void Dispose(bool disposing)
    {  
        if (disposing)
        {
            http?.Dispose();  
        }  
    }  
}

Read more about disposable pattern here. I never forget to use using statement for my disposable objects to make sure the dispose method gets called:

using (var api = new ApiClient()) 
{
    // use api
}
Andrei
  • 42,814
  • 35
  • 154
  • 218
  • There's no reason to suppress the finalizer of an object that doesn't have a finalizer. There's also no reason to have a parameter indicating whether or not the object is being disposed in a finalizer when you don't have a finalizer. – Servy Jun 29 '17 at 15:31
  • Now you have a finalizer for an object that doesn't actually have anything to actually do. You shouldn't be adding finalizers to objects that don't actually have anything to clean up in their finalizers. – Servy Jun 29 '17 at 15:40
  • @Servy I'd love to see your **correct** answer – Andrei Jun 29 '17 at 15:45
  • See the duplicate, it has numerous good answers on the subject. – Servy Jun 29 '17 at 15:54