不能得到异常&Dispose()在这个方法中工作
本文关键字:方法 工作 异常 Dispose 不能 | 更新日期: 2023-09-27 18:11:07
我有以下从火鸟数据库读取的函数。该函数工作,但不处理异常(必需)。
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的错误。我理解为什么我得到错误,但我尝试过的任何解决方案都导致DBReader通过使用()过早地间接处置或Dispose()未被调用all。我如何让这段代码使用异常&清理而不必包装方法或复制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;
}
对我来说,你得到的代码看起来很好(除了我将在yield return周围使用大括号,并更改变量名以适应。net命名约定:)
Dispose
方法只有在以下情况下才会在reader上被调用:
- 读取
MoveNext()
或Current
时抛出异常 - 使用迭代器的代码对其调用dispose
注意,foreach
语句会自动调用迭代器上的Dispose
,所以如果您写:
foreach (DbDataRecord record in ExecuteQuery())
{
if (someCondition)
{
break;
}
}
则会在块末尾的迭代器上调用Dispose
,然后在FbDataReader
上调用Dispose
。换句话说,它应该都按预期工作。
如果您需要在方法中添加异常处理,则需要执行如下操作: 就我个人而言,我会在更高的级别处理异常…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;
}
}
}
这行不行,注意最后的;
,它是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的回答。