Search code examples
c#wpfexceptionobjectdisposedexception

ObjectDisposedException in c# database connection class


I am new to C#, I am programming an app in c# that requires the connection of an sqlite database. I thought it would be easiest for me to create my own DBConnection class, which I have given below. The main problem I am having at the moment is with the destructor. Sometimes when I instantiate this class and it goes out of scope, I get a

System.ObjectDisposedException; 'Cannot access a disposed object. Object name: 'SQLiteConnection'.'

Now I have searched for a definition of what this means, but I don't really understand.

The object is being instantiated as part of a wpf app window, and this exception is thrown once the window is x'd out, and after database operations are finished.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Data.SQLite;
using System.IO;

namespace PhotoSuppliesInc
{
    //this class will be used for connecting to the database in the various forms
    public class DBConnector
    {
        //----------------------------------PRIVATES------------------------------//
        //this is the connection to the db
        private SQLiteConnection dbConnection;

        //-------------------CONSTRUCTOR(S) and DESCTRUCTOR----------------//
        public DBConnector()
        {
            string connectionString = "Data Source=C:\\Users\\dmand\\source\\repos\\PhotoSuppliesInc\\PhotoSuppliesInc\\database\\riverfrontphoto.db;" +
                                            "Version = 3; FailIfMissing=True; Foreign Keys=True;";
            try
            {
                dbConnection = new SQLiteConnection(connectionString);
                dbConnection.Open();
                MessageBox.Show("Database connected successfully");
            }//end try
            catch (SQLiteException e) { MessageBox.Show("error opening database"); }
        }//end constructor
        //destructor removes connection to database
        ~DBConnector()
        {
                dbConnection.Close();
        }
        //--------------------------------------------------GETTER(S)------------------------//
        //public string Get_Filepath() { return filepath; }

        //--------------------------------------------------UTILITY FUNCTIONS----------------//
        public List<string> Select_Query(string query_string, string columns)
        {
            //the names of the columns in the select statement
            string[] selection_columns = columns.Split();
            //each member of the array is the tuple, the data is separated by spaces
            List<string> result = new List<string>();
            //this string constructs the result line to be inserted into the result list
            string tempstring;
            SQLiteCommand command = new SQLiteCommand(query_string, dbConnection);
            SQLiteDataReader reader = command.ExecuteReader();
            while (reader.Read())
            {
                tempstring = "";//reset the temp string for each tuple
                int i = 0;
                foreach(string s in selection_columns)
                {
                    tempstring += reader[s] + " ";
                    i++;
                }
                //I'm not sure why result.add must go here, but it does
                result.Add(tempstring);
            }
            //the result is a list who's contents are strings that represent each tuple
            return result;
        }
    }//end class
}//end namespace

///////in LoginWindow.xaml.cs////

This how I am using the class in the window code file. ...

public LoginWindow()
{
    itializeComponent();

    //testing the DBConnector class:
    DBConnector riverfront = new DBConnector();
    string output_string = "";
    foreach (string s in riverfront.Select_Query(@"select distinct fname || ' ' || lname as 'Full_Name', country from employee, employee_account limit 5", "Full_Name country"))
        output_string += s + "\n";
        MessageBox.Show(output_string);
    }
...

As I said I don't know what this error means, or if I am properly using the destructor in this language. It seems to me like there should be no problem here. Can somebody help me figure out what this error means in my class? Thank you all for your time.


Solution

  • You are not properly using "destructors" because C# does not have destructors, it has finalizers.

    The proper way to do what you're trying to do is to implement the IDisposable pattern and access instances of your class within using blocks.

    Finalizers (denoted by the ~ syntax) are non-deterministic -- you cannot control when the garbage collector runs the finalizer, or if it ever does. Implementing IDisposable and accessing instances within a using block allows you to implement deterministic cleanup of resources.

    This is why you're getting an ObjectDisposedException: Your class's finalizer is running after your instance of SQLiteConnection is disposed.