Search code examples
c#winformsidisposableobjectdisposedexceptionlitedb

Prevent object dispose inside using block


Workflow:

I have a winform app with two forms, in the 1st form I query a liteDB and it manipulates an IEnumerable<T> instance inside a using block with retrieved data.

IEnumerable<student> searchResult;
using(var db = new LiteDatabase(@"C:\Temp\MyData.db"))
{
    var col = db.GetCollection<student>("students");
    col.EnsureIndex(x => x.contact.phone);
    searchResult = col.Find(x => x.contact.phone == "123456789");
}
Form2 frm2 = new Form2();
Form2.profileData = searchResult.AtElement(index);

Problem:

I then, need to send an element of searchResult<student> to 2nd form in order to show user, as you can see in the last 2 lines of above code.
But since it's inside using block, I get System.ObjectDisposedException.

Data types and exception:

studentCollection.Find(): studentCollection.Find() searchResult: enter image description here Exception: enter image description here Addition:

What I already though of as possible way is:
Override and nullify existing dispose() method then call my own implemented method after I'm done; Which is basically equals to not having a using block, except that I don't have to take care of disposing other objects in above using block, but only searchResult<student>.

P.S: I'm newbie at whole thing, appreciate the help and explanation


Solution

  • I'm not familliar with LiteDb, but I would assume it returns a proxy object for the database. So when the database is disposed, the proxy-object is no longer usable.

    The simple method to avoid the problem is to add .ToList() after the .Find(...). This will convert the proxy-list to an actual List<T> in memory, and it can be used after the database is disposed. It is possible that the student objects inside the list are also proxies, and if that is the case this will fail.

    If that is the case you either need to find some way to make the database return real, non-proxy objects, or extend the lifetime of the database to be longer than that of your form, for example

    IList<student> myIList;
    using(var db = new LiteDatabase(@"C:\Temp\MyData.db"))
    {
        var col = db.GetCollection<student>("students");
        col.EnsureIndex(x => x.contact.phone);
        myIList = col.Find(x => x.contact.phone == "123456789");
        using(var frm2 = new Form2()){
           frm2.profileData = myIList.AtElement(index);
           frm2.ShowDialog(this);
        }
    }
    
    

    Note the usage of .ShowDialog, this will block until the second form has been closed. That is not strictly necessary, but it makes it much easier to manage the lifetime of the database.