Не могу получить исключения и Dispose () для работы в этом методе - PullRequest
0 голосов
/ 13 октября 2011

У меня есть следующая функция, которая читает из базы данных 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 к этой функции приводит к ошибке относительно выхода.Я понимаю, почему я получаю ошибку, но любая попытка работы, которую я пробовал, приводила к косвенному удалению 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;

    }

Ответы [ 2 ]

1 голос
/ 13 октября 2011

Эта строка не будет работать, обратите внимание на ; в конце, это вся область действия 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;  
    }

Чтобы также отлавливать ошибки из цикла чтения, смотрите статью Джона Скита.ответ.

1 голос
/ 13 октября 2011

Код, который вы получили, выглядит для меня нормально (за исключением того, что я бы также использовал фигурные скобки вокруг возвращаемого результата и изменил имена переменных, чтобы они соответствовали соглашениям об именах .NET):

The *Метод 1003 * будет вызываться только в считывателе, если:

  • При обращении к 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;
        }
    }
}

Лично я бы обработал исключение на более высоком уровне, хотя ...

...