views:

64

answers:

4

I use code rush and refactor pro (highlight possible code issues and so on like ReSharper) and they were telling me I had undisposed locals (that implemented IDisposable). So I changed the code to this with two using statements:

using (Reports.StudentRegisters.StudentQueriesDataTable studentDataTable = new Reports.StudentRegisters.StudentQueriesDataTable())
        {
            using (StudentQueriesTableAdapter studentTableAdapter = new StudentQueriesTableAdapter())
            {
                try
                {
                    studentTableAdapter.FillByQAbsenceRegRow(studentDataTable, year, school, division, progArea, sinceWeek, missedLessons, includeWdlTrn, ageMin, ageMax, studentGLH);
                    ds = new DataSet();
                    ds.Tables.Add((DataTable)studentDataTable);
                    ReportDocument.SetDataSource(ds.Tables[0]);
                }
                catch (Exception err)
                {
                    LogReportError(err, this.CrystalViewer, null, ErrorType.Reporting);
                }
            }
        }

Since the studentTableAdapter is used once I could in line it like below:

using (Reports.StudentRegisters.StudentQueriesDataTable studentDataTable = new Reports.StudentRegisters.StudentQueriesDataTable())
        {
                try
                {
                    (new StudentQueriesTableAdapter()).FillByQAbsenceRegRow(studentDataTable, year, school, division, progArea, sinceWeek, missedLessons, includeWdlTrn, ageMin, ageMax, studentGLH);
                    ds = new DataSet();
                    ds.Tables.Add((DataTable)studentDataTable);
                    ReportDocument.SetDataSource(ds.Tables[0]);
                }
                catch (Exception err)
                {
                    LogReportError(err, this.CrystalViewer, null, ErrorType.Reporting);
                }
        }

Obviously in this solution I now have no way to call dispose on the StudentQueriesTableAdapter. Is this called automatically as there is no reference to the object anymore or would this potentially leave something not disposed properly.

I will stress i'm not interested in whether I actually need to use dispose on the two objects, I know some things implement it and it's not really required (Although should always be done). I'm specifically interested in if it is called.

+1  A: 

Dispose() isn't called automatically on objects that go out of scope - you need to wrap a reference to StudentQueriesTableAdapter in a using() {...} for it to be disposed correctly.

Another option is to combine the using and try, to reduce the nesting somewhat:

using (Reports.StudentRegisters.StudentQueriesDataTable studentDataTable = new Reports.StudentRegisters.StudentQueriesDataTable())
    {
        StudentQueriesTableAdapter studentTableAdapter;

        try
        {
            studentTableAdapter = new StudentQueriesTableAdapter();
            studentTableAdapter.FillByQAbsenceRegRow(studentDataTable, year, school, division, progArea, sinceWeek, missedLessons, includeWdlTrn, ageMin, ageMax, studentGLH);
            ds = new DataSet();
            ds.Tables.Add((DataTable)studentDataTable);
            ReportDocument.SetDataSource(ds.Tables[0]);
        }
        catch (Exception err)
        {
            LogReportError(err, this.CrystalViewer, null, ErrorType.Reporting);
        }
        finally
        {
            if (studentTableAdapter != null)
                studentTableAdapter.Dispose(); // or Close(), depending on which method is public
        }
    }

This is essentially what a using {} does - wrap it in a try/finally clause

Note that, although some objects may implement IDisposable with the Dispose method not doing anything, you should always wrap any IDisposable objects in a using - it is part of the contract of using that class, otherwise you may end up leaking resources (eg if an empty Dispose method is later filled out in a future version)

thecoop
+1  A: 

While it's part of the spec to have an item that implements IDisposable to have a finalizer that performs that call if it wasn't performed earlier, this is a bad, bad habit. If you instantiate an object that implements IDisposable and are finished with it, call Dispose.

Adam Robinson
Part of what spec? When I implement IDisposable, I usually do Debug.Assert(false) in the finalizer, just to make sure that I learn ASAP if I forget disposing something.
erikkallen
@erik: see http://msdn.microsoft.com/en-us/library/system.idisposable.aspx for more information. If you design a `IDisposable` component/class, you should always implement a finalizer that releases *unmanaged* resources (but no managed resources). This is the pattern of having a `Dispose(bool disposing)` overload, with `Dispose()` passing `true` and the finalizer passing `false`.
Adam Robinson
I consider this more of a suggested implementation than part of the spec.
erikkallen
@erik: You're certainly entitled to your opinion :)
Adam Robinson
It is an important part of the coding style, because if someone wants to derive a class from your class which implements `IDisposable`, he'd expect that pattern (and if you do not provide it, then you force your choice on him as well, as he has no way to implement it correctly without the base class implementing it that way). As well, C++/CLI `ref class` destructors/finalizers are also combined together using this pattern. All in all, it's definitely better to follow it (which doesn't preclude you from putting asserts in your finalizers, by the way).
Pavel Minaev
+1  A: 

Dispose is only called on objects that implement IDisposable() which you use using block on.

Thanks

Mahesh Velaga
+4  A: 

No, it will not get called. Using(foo){ DoSomething() } is (roughly) functionally equivalent to:

var objectToDispose = foo as IDisposable;
try
{
    DoSomething();
}
finally
{
    if(objectToDispose != null)
        objectToDispose.Dispose();
}

Because of this, your StudentQueriesTableAdapter does not get disposed.

I often try to reduce nesting with multiple disposes like this:

using (var foo = new Foo())
using (var bar = new Bar(foo))
{
    DoSomething();
}
Brian Genisio
I like your double using technique that makes it look tidier to me. The nesting is the main reason I didn't like my original code layout.
PeteT
Yeah, that's the idiomatic way to format nested `using` blocks to avoid extra indentation.
Pavel Minaev