JohnS said:
Thanks again for your insight. Unfortunately it just doesn't work out
very well in this case. First, "DataRow" doesn't inherit from
"IDisposable" which puts the onus on the user to explicitly call
"DataRow.Table.Dispose()" (instead of putting a "using" statement around
"DataRow").
Yes, I know. I acknowledged that in my follow-up reply to my own post.
That's not really a problem at all though.
This is hardly elegant to say the least and certainly
error-prone to expect undisciplined programmers to constantly do this
(just the reality).
As I pointed out, there are multiple ways to approach the problem.
Passing the DataTable back is not necessarily the best way to solve it
in your case, but that doesn't mean it's never going to be the best way
to solve it.
Cloning or copying tables of data is also grossly
inefficient for a DB application in particular and probably even more
problematic in this case, since I would have to clone types that are
created by the Visual Studio forms designer itself.
First: if you would find yourself cloning the _table_, then it actually
makes more sense to pass the table back in the first place. If you're
only cloning a row of data for a specific purpose, that is trivial
overhead and not a problem at all.
Second: note that the cloning does not literally have to produce the
same type (though in most cases, even for Designer-generated types, this
shouldn't be much of a problem). The point is to extract the data you
need and return that in some useful way.
Not sure if this is
doable at all off-hand - would have too look into it but it almost
certainly means more overhead when less is always better. Returning the
"DataTable" object itself is also syntactically ugly when the table
contains just one row in these cases (used for key searches, etc.).
Frankly, IMHO creating a whole table when just one row would do is ugly.
How can you worry about the overhead involved in copying some data
from a container to a more stable format you can use, when your entire
implementation is using a much higher overhead approach than is required?
It's
always the first and only row in the table users are after so returning
the row is much cleaner. I'm resigned at this point to not worry about
disposing of these "DataTable" objects for now since AFAIK, they consume
no unmanaged resources I probably have to worry about.
Perhaps it's because I don't use the database classes much, but it's not
clear to me why, if DataRow itself isn't disposable, having the parent
DataTable object disposed is a problem. Just because an object
implements IDisposable, that doesn't mean that every piece of
information you might get from it becomes invalidated when the object
itself is disposed.
And this is doubly true if you really believe that the
DataTable.Dispose() method doesn't do anything useful. How could it
cause a problem at all to return a DataRow from a DataTable that has
been disposed, if disposing the DataTable itself does nothing?
That is, they
pick up "IDisposable" further up the hierarchy and various discussions
about it on the web seem to confirm this. It's ultimately a trade-off
however between pedantic adherence to proper "IDisposable" rules (which
I'd prefer to follow), vs the trouble it's causing in this case.
Note that if you're keeping a reference to a DataRow obtained from the
DataTable, between the two options "dispose the DataTable" and "don't
dispose the DataTable", the current behavior appears to be mostly the
same either way, with some specific exceptions:
– A class that implements IDisposable also has a finalizer. Objects
with finalizers cannot be collected as quickly as those without, so even
ignoring anything else, failing to dispose such objects will make your
code run more poorly.
– A class that implements IDisposable where disposing today doesn't
release unmanaged resources is not necessarily going to have that
characteristic in the future. If and when that happens, failing to
release unmanaged resources will cause even more significant problems to
the execution of the code.
– If you do choose to dispose the DataTable, but keep the reference
to the DataRow, then there may never be any problem with that. There's
nothing obvious about a DataRow that suggests the parent DataTable has
to remain undisposed for the DataRow instance itself to remain useful.
– Even if in the future, using the DataRow when the DataTable has
been disposed is a problem, the manifestation of that problem will be
immediate and easily observed. On the other hand, failure to manage
memory correctly can and will manifest itself in much more subtle and
harder-to-track ways. By the time that failure is an actual problem,
you may not even be the one maintaining the code, but even if you are,
the chances that you will immediately realize the problem is tied to the
failure to dispose an object in a specific place in the code is
practically nil.
My personal opinion is that there's a much more correct approach to this
problem, and that involves either moving management of the lifetime of
the DataTable to the consuming code, or simply not even depending on the
DataTable outside the method where you dispose it, by copying the data
of interest and returning that.
Even better would be to not design the code so that you go to all the
trouble of creating a whole DataTable instance just to get one row's
worth of data.
But, if you insist on doing something incorrect, IMHO the much better
incorrect choice to make is to dispose the DataTable and return the
DataRow anyway. This will be much more maintainable going forward, as
it's more efficient even today (suppressing finalizing of the object)
and if the object should in fact require disposal in the future, any
failure that might occur will be easily fixed, rather than lurking as a
hard-to-discover program efficiency and resource management problem.
Pete