I have the following function which reads from a firebird database. The Function works but does not handle exceptions (Required).
public IEnumerable<DbDataRecord> ExecuteQuery(string Query)
{
var FBC = new FbCommand(Query, DBConnection);
using (FbDataReader DBReader = FBC.ExecuteReader())
{
foreach (DbDataRecord record in DBReader)
yield return record;
}
}
Adding try/catch to this function gives an error regarding yield. I understand why I get the error but any workround I’ve tried has resulted in DBReader being disposed indirectly via using() too early or Dispose() not being called all. How do I get this code to use Exceptions & Cleanup without having to wrap the method or duplicate DBReader which might contain several thousand record?
Update:
Here is an example of an attempted fix. In this case DBReader is being disposed too early.
public IEnumerable<DbDataRecord> ExecuteQuery(string Query)
{
var FBC = new FbCommand(Query, DBConnection);
FbDataReader DBReader = null;
try
{
using (DBReader = FBC.ExecuteReader());
}
catch (Exception e)
{
Log.ErrorException("Database Execute Reader Exception", e);
throw;
}
foreach (DbDataRecord record in DBReader) <<- DBReader is closed at this stage
yield return record;
}
The code you’ve got looks fine to me (except I’d use braces round the yield return as well, and change the variable names to fit in with .NET naming conventions 🙂
The
Disposemethod will only be called on the reader if:MoveNext()orCurrentin the reader throws an exceptionNote that a
foreachstatement callsDisposeon the iterator automatically, so if you wrote:then that will call
Disposeon the iterator at the end of the block, which will then callDisposeon theFbDataReader. In other words, it should all be working as intended.If you need to add exception handling within the method, you would need to do something like:
Personally I’d handle the exception at the higher level though…