I am checking for Null in the code below, even when passed a bogus path the null test is passed. However when I return the workbook a NullPointerException is thrown. How can I check for a NullPointerReference in this case? When I inspect the workBook variable while debugging it is set to something, I believe this must be why it is passing the Null check.
public static ExcelWorkbook OpenExcelWorkSheet(string file_path)
{
string EXCEL_FILE_EXTENSION = ".xlsx",
full_path = file_path + EXCEL_FILE_EXTENSION;
var excelFile = new FileInfo(full_path);
using (var package = new ExcelPackage(excelFile))
{
ExcelWorkbook workBook = package.Workbook;
if (workBook.Equals(null))
{
throw new Exception("ERROR!!!");
}
else { Console.Write("not null"); }
return workBook;
}
}
Looking at the source code for ExcelPackage, the Workbook property can never return null. Its getter will create a new Workbook if it finds that its internal field is null:
public ExcelWorkbook Workbook
{
get
{
if (_workbook == null)
{
var nsm = CreateDefaultNSM();
_workbook = new ExcelWorkbook(this, nsm);
_workbook.GetExternalReferences();
_workbook.GetDefinedNames();
}
return (_workbook);
}
}
Knowing this, I think you could safely remove the check altogether.
Additionally, as others have noted, you do need to be careful about how you use your using statements. When a ExcelPackage is disposed, its Workbook is in turn disposed (you can see this happening in the source code I linked). This is probably why you're seeing a null workbook returned from your method, but not while you are in the using statement. Very shortly after that closing } of your using it becomes null.
If you have a class that you're using to wrap the functionality of EPPlus, then you should make sure that it:
Only instantiates the ExcelPackage once and holds onto a reference to it; do not use a using statement when you do this
Have your other methods access this ExcelPackage reference when they need to; don't pass it around or re-open the package
Implement IDisposable, then properly dispose your ExcelPackage object when your wrapper is disposing.
Here's an example*:
public class YourWrapper : IDisposable
{
private bool disposed;
public YourWrapper()
{
}
public YourWrapper(string path)
{
OpenExcelPackage(path);
}
public void OpenExcelPackage(string path)
{
Package = new ExcelPackage(path);
}
public ExcelPackage Package { get; private set; }
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
if (Package != null)
{
Package.Dispose();
Package = null;
}
}
}
this.disposed = true;
}
~YourWrapper()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
Now instead, use a using whenever you instantiate your wrapper:
using (var wrapper = new YourWrapper())
{
// Do everything related to manipulating the Excel file here
}
And everything will get cleaned up nicely.
* Please change the names of the classes/methods to something more appropriate; this was just for illustration.
Related
In C# an ExcelApp is created in the constructor, when I try to use the same App in the destructor I get the squiggly line saying that 'The App does not exist in the current context'
using Excel = Microsoft.Office.Interop.Excel;
namespace Analysis
{
class OutputFile
{
OutputFile()
{
Excel.Application ExcelApp = new Excel.Application();
}
interface IOutputFile
{
}
~OutputFile()
{
ExcelApp.Close();
ExcelApp.Quit();
}
}
}
You have 2 problems:
Your object ExcelApp is only scoped to the constructor, but looks like to it should be a class member or a property.
Finalizers are not the right solution for this sort of use case in C#; implement IDisposable interface instead:
class OutputFile : IDisposable
{
Excel.Application ExcelApp { get; set; }
public OutputFile()
{
ExcelApp = new Excel.Application();
}
public void Dispose()
{
ExcelApp.Close();
ExcelApp.Quit();
}
}
Usage:
using(var outputFile = new OutputFile())
{
// do stuff with output file
}
Once outputFile goes out of scope (at the end of the using block), the Dispose() method will be called by the Garbage Collector (GC). Note, this will happen even if an exception occurs inside the using block, as this code is a shorthand for:
var outputFile = new OutputFile();
try
{
// do stuff with output file
}
finally
{
outputFile.Dispose();
}
Since you're new to C#, I will link the documentation references for using statement, IDisposable, and Finalizers
Happy learning!
I would like to optionally dispose (with a using statement) an object. If the connection string is passed in the constructor, then the using must dispose and if the object SQLDataLayer is passed in the constructor, then I don't want to dispose. This is to avoid passing the SQLDataLayer object in every re-usable method, is this the right approach?
public class RepoCategory
{
readonly string connString;
SQLDataLayer dl = null;
public RepoCategory(string conn_string)
{
this.connString = conn_string;
}
public RepoCategory(SQLDataLayer dl)
{
this.dl = dl;
}
//I WANT TO MAGICALLY generate using(null) if dl was passed in constructor
//or using(dl = new SQLDataLayer(connString)) if connString was passed.
public Category Get(int category_sid)
{
Category cat = null;
using (SQLDataLayer dlDispose = (dl == null) ? new SQLDataLayer(connString) : null)
{
//can this be simplified/avoided?
if (dlDispose != null)
dl = dlDispose;
cat = dl.GetCat();
}
return cat;
}
//I DON'T WANT TO PASS THE DL MANUALLY EVERYTIME
public Category Get(SQLDataLayer dl, int category_sid)
{
Category cat = null;
cat = dl.GetCat();
return cat;
}
}
thanks!
using is just short hand for
try
{
obj = new Obj();
}
finally
{
obj.Dispose();
}
You can call Dispose directly if you want. Just do try / finally and in the finally go if(xxx) obj.Dispose()
You don't need to declare variables in a using statement.
You can make a using statement that only does anything in some circumstances:
SQLDataLayer dl = ...;
using(someCondition ? dl : null) {
...
}
In your particular example, like this:
SQLDataLayer dlDispose = null;
SQLDataLayer dl = this.dl ?? (dlDispose = new SQLDataLayer(connString));
using (dlDispose) { dl.Blah(...) }
This also fixes the bug where you leave the class field referring to a short-lived connection that you're also disposing.
For more general usefulness, it is helpful to have a holder class that implements Dispose and will conditionally call Dispose on the object it holds.
I am making an application for a 'Ski Resort' where you can add members and search members etc. So far I am having difficulty saving and loading these when the application closes. When I add a member, it saves, and then when I try to add another, the first member will not be saved anymore but the first one will have done.
Here is the code used to Save the members:
public void Save(System.IO.TextWriter textOut)
{
textOut.WriteLine(number);
textOut.WriteLine(name);
textOut.WriteLine(address);
textOut.WriteLine(score);
textOut.Close();
}
public bool Save(string filename)
{
System.IO.TextWriter textOut = null;
try
{
textOut = new System.IO.StreamWriter(filename);
Save(textOut);
}
catch
{
return false;
}
finally
{
if (textOut != null)
{
textOut.Close();
}
}
return true;
}
The StreamWriter constructor you are using will overwrite the file each time. Use the constructor that also takes a boolean so you can make it append to the file. And you don't need the TextWriter.
try
{
using(var textOut = new System.IO.StreamWriter(filename, true))
{
textOut.WriteLine("whatever..");
}
}
I have an object which is used to access a SQL Server table, do insert / updates.
I have two windows services, which use the same object to read/write to the same table.
To preserve the integrity, I was using Mutex lock and release on this object. But of late getting sync errors (Object synchronization method was called from an unsynchronized block of code). Hence I am adding a bool to identify the caller (In the code below bool isThreadOwnedLockAskingToRelease in 'Release' method). Will this resolve the sync issues and is this the correct way?
Class ST
public ST() //constructor
{
Mutex stBusy = utils.GetMutex(#"ST");
bool lockAcquired = false;
lock (ex)
{
//open connection
// build dataset
// close conn
}
}
// ...
public bool Lock(string nameOfLock)
{
if (stBusy != null)
{
if (stBusy.WaitOne(2000))
{
lockAcquired = true;
//...
}
}
return lockAcquired;
}
public void Release(string NameOfUnlocker, bool isThreadOwnedLockAskingToRelease)
{
if (stBusy != null && isThreadOwnedLockAskingToRelease)
{
stBusy.ReleaseMutex();
}
}
Class Service1:
ST st;
bool smlock = st.Lock("STLock");
if (smlock)
{
st = new ST(); // construct object
// do work
st.Release("STLock",smlock); // 2nd param added to identify the locker
}
Class Service2:
ST st1;
bool lockOwner = st1.Lock("QM");
st1= new StatusTable();
//Do work
// Unlock the status table
st1.Release("QM", lockOwner); // Addl. parameter added to fix sync issue
I have the following class:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using MySql.Data.MySqlClient;
namespace DataBaseModule.General
{
public class ManagedDataReader : IDisposable
{
private bool _disposed = false;
private MySqlCommand _command;
private MySqlDataReader _dataReader;
// The class constructor.
public ManagedDataReader(string StrSQL)
: this(new MySqlCommand(StrSQL))
{
}
public ManagedDataReader(MySqlCommand SQL_Cmd)
{
try
{
_command = SQL_Cmd;
_command.Connection = new MySqlConnection(DbAccessProvider._connectionString);
DbAccessProvider.SqlCommandsPerformed++;
_command.Connection.Open();
_dataReader = _command.ExecuteReader();
}
catch (Exception ex)
{
DataBaseModule.Log.CommonLogger.Log_Database_Error(new Exception("Sql command Was: " + _command.CommandText, ex));
throw ex;
}
}
public int VisibleFieldCount()
{
return _dataReader.VisibleFieldCount;
}
public bool Read()
{
return _dataReader.Read();
}
public object this[int i]
{
get
{
if (_dataReader[i].Equals(DBNull.Value))
{
return null;
}
else
{
return _dataReader[i];
}
}
}
public object this[string FieldName]
{
get
{
if (_dataReader[FieldName].Equals(DBNull.Value))
{
return null;
}
else
{
return _dataReader[FieldName];
}
}
}
// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
protected void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if (!this._disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if (disposing)
{
if (_dataReader != null)
{
_dataReader.Close();
}
if (_command != null)
{
if (_command.Connection != null)
{
_command.Connection.Dispose();
_command.Connection = null;
//Free the reference.
}
_command.Dispose();
}
}
// Call the appropriate methods to clean up
// unmanaged resources here.
// If disposing is false,
// only the following code is executed.
// Note disposing has been done.
_disposed = true;
}
}
// This finalizer will run only if the Dispose method
// does not get called.
// It gives your base class the opportunity to finalize.
// Do not provide finalize methods in types derived from this class.
~ManagedDataReader()
{
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
Dispose(false);
}
}
}
My problem is that for some reason, sometimes i got exception when calling Read():
the exception is that my _dataReader member is null.
That's weird, because i have try-catch block on its initialization, and no exception is caught (i use my loging mechanism to check this).
This behavior is rare, but occures aprox. once a week (i'm running milions of queries per day)
Thanks a lot to anyone who tries to solve this mistery!!
I came up with the same problem. And it turned out that ExecuteReader () can actually return null in some cases.
I looked up the code of the connector and this is what I found:
catch (MySqlException ex)
{
...
// if we caught an exception because of a cancel, then just return null
if (ex.IsQueryAborted)
return null;
Digging a little deeper turns out IsQueryAborted is true when the server returns MySqlErrorCode.QueryInterrupted or MySqlErrorCode.FileSortAborted. And so far it turns out that this is some server problem as at least in my case the problem is not consistent and looks like a multi-threading issue in the server code.
I reviewed the code and I find the only way to get with NULL reader is to have an exception in the initialization code.
As SqlDataReader.ExecuteReader is return an object in all cases and can't return null. Tatiana Racheva had confirmed that by reflection SqlDataReader class in this answer.
The second scenario to have NULL reader is if you are trying to use the reader after your ManagedDataReader object is disposed by the garbage collector.