C# 无法获得例外&;Dispose()以在此方法中工作

C# 无法获得例外&;Dispose()以在此方法中工作,c#,exception,firebird,C#,Exception,Firebird,我有以下从firebird数据库读取的函数。该函数工作,但不处理异常(必需) public IEnumerable ExecuteQuery(字符串查询) { var FBC=新的FBC命令(查询、数据库连接); 使用(FbDataReader DBReader=FBC.ExecuteReader()) { foreach(DBReader中的DbDataRecord记录) 收益回报记录; } } 将try/catch添加到此函数会导致有关产量的错误。我理解为什么会出现错误,但我尝试过的任何解

我有以下从firebird数据库读取的函数。该函数工作,但不处理异常(必需)

public IEnumerable ExecuteQuery(字符串查询)
{
var FBC=新的FBC命令(查询、数据库连接);
使用(FbDataReader DBReader=FBC.ExecuteReader())
{
foreach(DBReader中的DbDataRecord记录)
收益回报记录;
}
}
将try/catch添加到此函数会导致有关产量的错误。我理解为什么会出现错误,但我尝试过的任何解决方法都会导致DBReader过早使用()而被间接处置,或者Dispose()没有被全部调用。我如何让这段代码使用异常和清理,而不必包装该方法或复制可能包含数千条记录的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;

    }
public IEnumerable ExecuteQuery(字符串查询)
{   
var FBC=新的FBC命令(查询、数据库连接);
FbDataReader DBReader=null;
尝试
{
使用(DBReader=FBC.ExecuteReader());
}
捕获(例外e)
{
ErrorException(“数据库执行读卡器异常”,e);
投掷;
}

foreach(DBReader中的DbDataRecord)我觉得您得到的代码很好(除了在收益率返回中使用大括号,并更改变量名以适应.NET命名约定:)

只有在以下情况下,才会对读取器调用
Dispose
方法:

  • 访问读取器中的
    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/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的答案。

请显示出现错误的代码,以及确切的错误是什么。处理异常是什么意思?我认为这个方法不能也不应该。请将捕获放在调用代码中。@Henk这个方法位于一个只用于与数据库对话的类中。所有她在类中的方法已经处理了异常,所以只是尝试维护一个标准。感谢她尝试了这一点,但不会编译2个错误“System.Collections.IEnumerator:using语句中使用的类型必须隐式转换为'System.IDisposable'”&“无法将类型'object'隐式转换为'System.Data.Common.DbDataRecord'。存在显式转换(是否缺少转换?)@Canacourse:我假设这是一个通用的
IEnumerable
。听起来好像不是-如果您能够使用LINQ,您可以使用
DBReader.cast().GetEnumerator()
    // 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;  
    }