-2

I write a class program with IDisposable. Now I want to dispose my managed and unmanaged memory. I am confused about the resources which are belong to managed and unmanaged memory.

I give class example:-

namespace WF2006toI4scada
 {
    public  class HelperClass : IHelperClass, IDisposable
    {

   static string  filename;
   static string aspfilename;
    private StreamReader file;
    static Excel.Workbook xlWorkBook;
   static Excel.Worksheet xlWorkSheet;
   static Microsoft.Office.Interop.Excel.Application application = new Microsoft.Office.Interop.Excel.Application();
   private   IDictionary<int, List<string>> vbsComponents;
   private IService  services;
   private bool IsDisposed = false;

    private static int totalNoofVBSElement = 0;


    private string projectsettinginifile;
    private static  HtmlDocument document2;
    private readonly ILogger loggerobject;

    public HelperClass()
    {
        loggerobject = Logger.Instance;
        application.Interactive = false;
    }

   
    public IDictionary<int, List<string>> VbsComponents { get => VbsComponents1; set => VbsComponents1 = value; }
    public string Filepath { get => filename; }
    public IDictionary<int, List<string>> VbsComponents1 { get => vbsComponents; set => vbsComponents = value; }
    public IService Services { get => services; set => services = value; }
    public string Projectsettinginifile { get => projectsettinginifile; set => projectsettinginifile = value; }
  
    public  string aspFilepath { get => aspfilename; }
    public HtmlDocument htmlDocument { get => document2; set => document2 = value; }
    

    public async Task ReadASPFileAsync()
    {        
       

            try
            {
                try
                {
                    loggerobject.debug("Browsing for ASP file started");
                    OpenFileDialog ofd = new OpenFileDialog();
                    ofd.Filter = "asp File |*.asp;*,asp";
                    if (ofd.ShowDialog() == DialogResult.OK)
                    {
                        string extn = Path.GetExtension(ofd.FileName);
                        if (extn.Equals(".asp"))
                        {
                            aspfilename = ofd.FileName;

                            file = new System.IO.StreamReader(aspfilename);

                            
                        }
                        else
                        {
                            throw new FileNotFoundException("File not found", ".asp");
                        }
                    }
                }


                catch (FileNotFoundException ex)
                {
                    new CustomSytemException("Caught this Error in ReadASPFileAsync function", DateTime.Now, ex);
                    loggerobject.exception(ex.Message, new SystemException("File not found  asp" , ex));

                }

                await Task.Run(() =>
                {
                    try
                    {
                        loggerobject.debug("Reading ASP file started");

                        if (!string.IsNullOrEmpty(aspfilename))
                        {
                            document2 = new HtmlDocument();
                            document2.Load(aspfilename);

                            if (object.ReferenceEquals(null, document2))
                            {
                                throw new FileReadingException("ASP file reading error", DateTime.Now);
                            }
                         

                        }

                       
                    }
                     
                    catch (FileReadingException ex)
                    {

                        new CustomSytemException("Caught this Error in ReadASPFileAsync function", DateTime.Now, ex);

                        loggerobject.exception(ex.Message, new SystemException("File not found  asp", ex));

                    }



                    catch(FileNotFoundException ex) 
                    {
                        new CustomSytemException("Caught this Error in ReadASPFileAsync function", DateTime.Now, ex);
                        loggerobject.exception(ex.Message, new SystemException("ASP file reading error", ex));


                    }

                });
            }


            catch (CustomSytemException ew)
            {
                MessageBox.Show(ew.ErrorTimeStamp + "\nErrror:" + ew.Message + "\n Inner strace:" + ew.InnerException.StackTrace + "\n Inner messege:"
                                   + ew.InnerException.Message + "\n" + ew.CauseOfError);

            }

    }

    /// <summary>
    /// This method use to read the .vbs file
    /// </summary>
    /// <returns></returns>       

    public async Task ReadVbsFileAsync()
    {
        loggerobject.debug("Reading VBS file started");
        bool opreation = false;
        OpenFileDialog ofd = new OpenFileDialog();
        ofd.Filter = "vbs File |*.vbs;*,vbs";
        if (ofd.ShowDialog() == DialogResult.OK)
        {
            string extn = Path.GetExtension(ofd.FileName);
            if (extn.Equals(".vbs"))
            {
                filename = ofd.FileName;

                if (filename != "")

                {
                    await Task.Run(() =>
                    {
                        try
                        {
                           
                            string vbsfilename = Path.GetFileName(filename);

                            object missing = System.Reflection.Missing.Value;
                            application.Visible = true;
                            

                            try
                            {
                                loggerobject.debug("VBS file to Excel converted started");
                                application.Workbooks.OpenText(Filename: filename, StartRow: 1,
                                DataType: Microsoft.Office.Interop.Excel.XlTextParsingType.xlDelimited, Tab: false);
                                if(application.Workbooks.Count == 0)
                                {
                                    throw new FileNotFoundException("File not found", ".vbs");
                                  
                                }
                                xlWorkBook = application.Workbooks[1];
                                xlWorkSheet = (Microsoft.Office.Interop.Excel.Worksheet)xlWorkBook.ActiveSheet;                            

                            }

                            catch(FileNotFoundException ex)
                            {
                                loggerobject.exception(ex.Message, new SystemException("File not found .vbs", ex));
                                throw new CustomSytemException("Reading VBS file error", DateTime.Now,ex);
                                
                            }



                            /*
                            Triming process for worksheet

                            */

                            try
                            {
                                loggerobject.debug("Excel Triming process started");

                                xlWorkSheet.Trim();
                                xlWorkSheet.TrimSpecialCharacter(Projectsettinginifile, Services);
                                opreation = true;
                                if(!opreation)
                                {
                                    new InvalidOperationException("X1worksheet file triming operation failed");

                                }
                            }

                            catch (InvalidOperationException ex)                                
                            {
                                loggerobject.exception(ex.Message, new SystemException("X1worksheet file triming operation failed", ex));
                                throw new CustomSytemException("Error in triming operation of xlWorkSheet ", DateTime.Now, ex);

                                

                            }

                            finally
                            {
                                opreation = false;

                            }


                            /*
                             Excel format is generated
                             create dictionary format tooltip and plcsignal
                             
                             */

                            try 
                            {
                                loggerobject.debug("Create dictionary of all VBS elemnts");

                                VbsComponents = (IDictionary<int, List<string>>)xlWorkSheet.CreateDictionary();

                                if ( object.ReferenceEquals(null, VbsComponents))
                                {
                                    throw new FileReadingException("Dictionary not generated from VBS file", DateTime.Now);                                     
                                    
                                }

                            }

                            catch(FileReadingException ex)
                            {
                                loggerobject.exception(ex.Message, new SystemException("Dictionary not generated from VBS file", ex));

                                throw new CustomSytemException("Dictionary not generated from VBS file", DateTime.Now,ex);
                            }                               

                            xlWorkBook.Close();

                        }

                        catch (CustomSytemException ew)
                        {
                            MessageBox.Show(ew.ErrorTimeStamp + "\nErrror:" + ew.Message + "\n Inner strace:" + ew.InnerException.StackTrace + "\n Inner messege:" 
                                +ew.InnerException.Message + "\n" + ew.CauseOfError );
                            application.Quit();
                        }

                        finally
                        {
                            application.Quit();

                        }
                    });

                }
            }
        }
    }

     public virtual void Dispose()
    {
        if (!IsDisposed)
        {
            IsDisposed = true;
            file.Dispose();
            application.Quit();
            Marshal.ReleaseComObject(application);  // only if you are the only holder of application
        }
    }
    
}

}

What are managed and unmanaged resources here and how to dispose them.

Could you please help me out to avoid memory leak.

Sangita Paul
  • 107
  • 7
  • You don't have to release managed memory - that's what is being managed for you. And unless you're doing something odd (I'm not seeing it in the code dump in the question) you won't be allocating unmanaged memory terribly often. So the answer to the question title is "Usually, nothing at all". – Damien_The_Unbeliever Aug 15 '22 at 07:54
  • `~HelperClass()` <-- You _really_ don't need a finalizer. – Dai Aug 15 '22 at 07:57
  • Microsoft.Office.Interop.Excel.Application application = new Microsoft.Office.Interop.Excel.Application(); and file = new System.IO.StreamReader(aspfilename);.....these are not unmanaged resources? – Sangita Paul Aug 15 '22 at 07:59
  • @Damien_The_Unbeliever,I call file and application in dispose method. It is not necessary – Sangita Paul Aug 15 '22 at 08:02
  • To a first approximation, it's enough to call `.Dispose` on things that implement `IDisposable` (ideally through a `using` block). The rest of memory management is handled by the garbage collector. Finalizers are needed only if your code *directly* contains unmanaged resources (handles, pointers), which is very rare -- `Excel.Application` is a *managed* wrapper around unmanaged resources (COM classes), and moreover, using it will not cause allocations in your own process, but in the Excel process. Calling `.Quit()` on the application object when you're done with Excel is enough. – Jeroen Mostert Aug 15 '22 at 08:36
  • 1
    @JeroenMostert Calling `Marshal.ReleaseComObject` might be necessary, especially in this case where it's holding the whole Excel application open, although for some strange reason the code appears to have that in a `static` field – Charlieface Aug 15 '22 at 11:40

1 Answers1

1

You do not have any unmanaged resources here, therefore the finalizer is not necessary.

  • Unmanaged resources are resources that have no representation at all in managed code, outside of something like an IntPtr handle or similar. In these cases you use a finalizer to ensure disposal. It's very rare to actually need to write one.
  • Managed resources are those which wrap an unmanaged one in an object that already has the full finalizer and Dispose(bool) pattern. For these, you do not need a finallizer, just a basic Dispose() function.

For clarity, remove the below code

~HelperClass()
{
    Dispose(false);
}

public void Dispose()
{
    //Pass true in dispose method to clean managed resources too and say GC to skip finalize in next line.
    Dispose(true);
    //If dispose is called already then say GC to skip finalize on this instance.
    GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposedStatus)
{
    if (!IsDisposed)
    {
        IsDisposed = true;
        // Released unmanaged Resources
        file.Dispose();
        application.Quit();

        if (disposedStatus)
        {
            // Released managed Resources
        }
    }
}

None of the above is necessary. All you need is the following.

public virtual void Dispose()
{
    if (!IsDisposed)
    {
        IsDisposed = true;
        file.Dispose();
        application.Quit();
        Marshal.ReleaseComObject(application);  // only if you are the only holder of application
    }
}

Note that if you manage the lifetime of the application object, you should also release it using Marshal.ReleaseComObject. It obviously should not be in a static field. Do not do this if other code is also holding that object.

Charlieface
  • 52,284
  • 6
  • 19
  • 43
  • If you're going to recommend removing the inheritable variant of the Dispose pattern, you ought to be recommending `sealed` also. Otherwise you leave a class that looks like it can be inherited from but which cannot use any new resources. – Damien_The_Unbeliever Aug 15 '22 at 13:42
  • 1
    You can always use an explicit interface implementation https://dotnetfiddle.net/IHHeJ7 but yes probably should be `virtual`. If a derived type introduces a finalizer then it can bring in the `Dispose(bool)` function also. – Charlieface Aug 15 '22 at 13:53
  • @Charlieface, Hi I have one doubt if I remove destructor how dispose function will be called. I edit my question. Please follow this. – Sangita Paul Aug 16 '22 at 09:06
  • It will be called from the `using`. You do have this object in a `using` when you create it right? That is how it should be called, do *not* rely on the finalizer to do cleanup as it's not guaranteed when or even if it will be called – Charlieface Aug 16 '22 at 09:52
  • @Charlieface No actually I call it as dependency injection using ninject module.please follow this. Bind().To().InSingletonScope(); Bind().To().InSingletonScope(); Bind().To().InSingletonScope(); Bind().To().InSingletonScope(); Bind().To().InSingletonScope(); Bind().To().InSingletonScope(); – Sangita Paul Aug 17 '22 at 04:37
  • What should I do in this case? – Sangita Paul Aug 17 '22 at 04:37
  • https://stackoverflow.com/a/10242470/14868997 – Charlieface Aug 17 '22 at 09:32