我有以下从firebird数据库中读取的函数。函数有效,但不处理异常(必需)。
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;
}
}
向此函数添加try / catch会产生有关yield的错误。我理解为什么我得到了错误,但是我尝试过的任何workround导致DBReader通过太早地使用()间接地处理或者没有全部调用Dispose()。如何让此代码使用Exceptions&amp;清理而不必包装方法或重复可能包含数千条记录的DBReader?
更新
以下是尝试修复的示例。在这种情况下,DBReader过早处置。
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;
}
答案 0 :(得分:1)
你得到的代码对我来说很好看(除了我还使用大括号围绕yield return,并更改变量名以适应.NET命名约定:)
只有在以下情况下才会在阅读器上调用Dispose
方法:
MoveNext()
或Current
会引发异常请注意,foreach
语句会自动在迭代器上调用Dispose
,所以如果你写了:
foreach (DbDataRecord record in ExecuteQuery())
{
if (someCondition)
{
break;
}
}
然后在块的末尾调用迭代器上的Dispose
,然后调用Dispose
上的FbDataReader
。换句话说,它应该都按预期工作。
如果您需要在方法中添加异常处理,则需要执行以下操作:
using (FbDataReader DBReader = FBC.ExecuteReader())
{
using (var iterator = DBReader.GetEnumerator())
{
while (true)
{
DbDataRecord record = null;
try
{
if (!iterator.MoveNext())
{
break;
}
record = iterator.Current;
}
catch (FbException e)
{
// Handle however you want to handle it
}
yield return record;
}
}
}
我个人会在较高级别处理异常......
答案 1 :(得分:1)
此行不起作用,请注意最后的;
,它是using()
的整个范围
try
{
using (DBReader = FBC.ExecuteReader())
; // this empty statement is the scope of using()
}
以下是正确的语法,除了你不能从try / catch中产生:
// not working
try
{
using (DBReader = FBC.ExecuteReader())
{
foreach (DbDataRecord record in DBReader)
yield return record;
}
}
catch (Exception e)
{
Log.ErrorException("Database Execute Reader Exception", e);
throw;
}
但您可以更接近原始代码:
// untested, ought to work
FbDataReader DBReader = null;
try
{
DBReader = FBC.ExecuteReader();
}
catch (Exception e)
{
Log.ErrorException("Database Execute Reader Exception", e);
throw;
}
using (DBReader)
{
foreach (DbDataRecord record in DBReader) // errors here won't be logged
yield return record;
}
要从读取循环中捕获错误,请参阅Jon Skeet的回答。