I am developing a class (in a C# MVC 5 project) that originally had a using
block within a single method, and it got to be very huge after placing formatting statements and other code in the using
block.
I am using the Nuget Epplus package to export a model's contents to an Excel document, and all of the tutorials I can find place the ExcelPackage
variable within a using
block.
using (ExcelProject excelProject = new ExcelProject())
{
// lots of code happens nere, making it bloated and ugly
}
In order to reorganize the class and make the ExportToExcel
method truly that -- something that only outputs a byte[] array and doesn't contain statements that can be moved into other methods -- I took the excelProject
variable out of the using
block and made it a class-level variable. That's when Visual Studio code analysis told me I needed to implement IDisposable
.
warning CA1001: Microsoft.Design : Implement IDisposable on 'EpplusExcelPackage' because it creates members of the following IDisposable types: 'ExcelPackage'.
I have encountered programmers who tell me things like, "Warnings are meant to be ignored! Turn them off!" I disagree with that and am making the time to address this warning.
I combed through the available IDisposable
tutorials and found inspiration for the three methods at the very bottom of the class: public void Dispose()
, protected virtual void Dispose(bool disposing)
, and ~EpplusExcelPackage()
.
Am I correctly implementing IDisposable in this class?
using OfficeOpenXml;
using System;
using System.Collections.Generic;
using System.Reflection;
// uses Nuget Epplus package
namespace WebApplication1.CentralFunctions
{
public class EpplusExcelPackage<T> : IDisposable
{
private IEnumerable<T> data;
private byte[] response;
private string worksheetTitle;
private ExcelPackage excelPackage = null;
private ExcelWorksheet worksheet;
public EpplusExcelPackage(IEnumerable<T> Data)
{
this.data = Data;
this.worksheetTitle = null;
excelPackage = new ExcelPackage();
CreateAndLoadWorksheet();
}
public EpplusExcelPackage(IEnumerable<T> Data, string WorksheetTitle)
{
this.data = Data;
this.worksheetTitle = WorksheetTitle;
excelPackage = new ExcelPackage();
CreateAndLoadWorksheet();
}
public void CreateAndLoadWorksheet()
{
excelPackage.Workbook.Worksheets.Add("Sheet1");
worksheet = excelPackage.Workbook.Worksheets[1];
worksheet.Name = "Sheet1";
worksheet.Cells[1, 1].LoadFromCollection(data, true);
}
public void IdentifyDataTypes()
{
// Gather type info of T properties.
PropertyInfo[] dataPropertiesInfos = typeof(T).GetProperties();
int i = 1;
foreach (System.Reflection.PropertyInfo dataPropertyInfo in dataPropertiesInfos)
{
if (dataPropertyInfo.PropertyType.ToString().Contains("[System.DateTime]"))
{
worksheet.Column(i).Style.Numberformat.Format = System.Globalization.DateTimeFormatInfo.CurrentInfo.ShortDatePattern;
}
i++;
}
}
public byte[] ExportToExcel()
{
response = excelPackage.GetAsByteArray();
return response;
}
/* Inspired by http://www.codeproject.com/Articles/413887/Understanding-and-Implementing-IDisposable-Interfa */
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing == true)
{
if (excelPackage != null)
excelPackage.Dispose();
}
else
{
// The example said nothing goes here.
}
}
~EpplusExcelPackage()
{
Dispose(false);
}
}
}
IDisposable
makes sense, the finalizer does not. \$\endgroup\$