0

I studying C# IDisposable now at ASP.NET MVC I implemented code like this,

using System;
using System.Collections.Generic;
using System.ComponentModel;

namespace DisposeTest.Controllers
{
    public class TestClass : IDisposable
    {
        private bool disposed = false;

        private Component component = new Component();
        private List<string> dataItem = new List<string>();

        ~TestClass()
        {
            Dispose(disposing: false);
        }

        public void Dispose()
        {
            Dispose(true);

            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {

                if (disposing)
                {
                    // DISPOSE MANAGED RESOURCE
                    component.Dispose();
                }

                // DISPOSE UNMANAGED RESOURCE
                dataItem = null;

                disposed = true;
            }
        }

        public void AddItem()
        {
            dataItem.Add("wwwwwwwwwwwwwww");
        }
    }
}
using System.Web.Mvc;

namespace DisposeTest.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            TestClass tc = new TestClass();

            tc.AddItem();
            tc.dispose();
            return View();
        }
    }
}

After When I push F5 to launch Visual studio debugger with web browser, debugger catch into destructor. But after I refreshed web browser again or hit enter browser address, debugger did not catch destructor.

I would like to know some answers.

  1. ASP.NET MVC call destructor after every controller action?
  2. Do I correctly used Dispose()?
  3. Should I clear variables even private member field?

Thank you for your your adivices

ps. I added to call dispose() method after doing add();

shunman
  • 227
  • 1
  • 2
  • 9
  • You *must* call Dispose yourself, preferably by using a `using` block. A finalizer (`~TestClass`) may *eventually* be called by the garbage collector – Hans Kesting Jan 18 '22 at 10:51
  • https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/using-objects – Hans Kesting Jan 18 '22 at 10:52
  • 2
    Your class doesn't contain any unmanaged resources, so there's no point having a finalizer or calling `GC.SuppressFinalize`. – Richard Deeming Jan 18 '22 at 11:13
  • `using TestClass tc = new TestClass(); ` – Aluan Haddad Jan 18 '22 at 11:31
  • The only thing you need to do in your parameterless Dispose method is call `component.Dispose`. The complex dispose pattern with a finalizer and a second Dipose method taking a Boolean is only relevant if you have unmanaged resources, i.e. resources not managed by .NET. Like Richard Deeming said this is not the case for you. – ckuri Jan 18 '22 at 17:01
  • 1
    Does this answer your question? [Implementing IDisposable correctly](https://stackoverflow.com/questions/18336856/implementing-idisposable-correctly) – Charlieface Jan 19 '22 at 01:28
  • @RichardDeeming you mean that member field "component" and "dataItem" clear after tc.dispose()? – shunman Jan 20 '22 at 05:25
  • @HansKesting Hello. I added tc.dispose() method – shunman Jan 20 '22 at 05:26
  • 1
    @shunman No, I mean that your class doesn't hold any unmanaged resources. It only hold references to other managed classes. A finalizer is only required if your class holds a reference to an unmanaged resource that isn't wrapped in a `SafeHandle`. – Richard Deeming Jan 20 '22 at 08:31

1 Answers1

1

For example. We have CatDataStore class who works with data base and implements IDisposable. This is full implements IDisposable:

class CatDataStore : IDisposable
{
    //data context contains models, connection string... etc
    private ApplicationDbContext _context = new ApplicationDbContext();
    private bool disposed;

    public async Task<bool> AddItem(Cat item)
    {
        await _context.Cats.AddAsync(item);
        await _context.SaveChangesAsync();
        return true;
    }
    //smth CRUD methods..

    
    public void Dispose()
    {
        Dispose(true);
        
        //GC can't eat this
        GC.SupressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (disposed)
                throw new ObjectDisposedException();
            _context.Dispose();
        }
        disposed = true;
    }

    ~CatDataStore() => Dispose(false);
}
Aarnihauta
  • 441
  • 3
  • 10
  • 1
    As with the code in the question, your class does not contain any unmanaged resources, so there's no point having a finalizer. Finalizers are only required for classes which hold unmanaged resources that aren't wrapped in a `SafeHandle`. – Richard Deeming Jan 20 '22 at 08:30