无法获得例外与优惠Dispose()在此方法中工作

时间:2011-10-13 19:00:14

标签: c# exception firebird

我有以下从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;

    }

2 个答案:

答案 0 :(得分:1)

你得到的代码对我来说很好看(除了我还使用大括号围绕yield return,并更改变量名以适应.NET命名约定:)

只有在以下情况下才会在阅读器上调用Dispose方法:

  • 在阅读器中访问MoveNext()Current会引发异常
  • 代码使用迭代器调用dispose就可以了

请注意,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的回答。