Search code examples
c#transactionsidisposabletry-catch-finallyyield-return

Yield return from a try/catch block


As Eric Lippert described in this article, yield return is not allowed within try/catch clauses.

Is there a nice way I could get something like this, without having to write my own IEnumerator by hand:

public IEnumerable<Data> GetData()
{
    var transaction = Session.BeginTransaction());
    try 
    {
        IQuery q = CreateQuery(session);

        foreach (var result in q.Enumerable())
            yield return ProjectResult(result);  // <-- doesn't work

        session.Commit();
    }
    catch (Exception ex)
    {
        transaction.Rollback();
        throw;
    }
    finally
    {
        transaction.Dispose();
    }
}

Solution

  • I'd just change the transaction-handling logic like this:

    public IEnumerable<Data> GetData()
    {
        var transaction = Session.BeginTransaction();
        bool rollback = true;
        try 
        {
            IQuery q = CreateQuery(session);
    
            foreach (var result in q.Enumerable())
            {
                yield return ProjectResult(result);
            }
    
            rollback = false;
            session.Commit();
        }
        finally
        {
            if (rollback)
            {
                transaction.Rollback();
            }
            transaction.Dispose();
        }
    }
    

    Or if your transaction supports the idea of "dispose means rollback unless it's commited":

    public IEnumerable<Data> GetData()
    {
        using (var transaction = Session.BeginTransaction();
        {
            IQuery q = CreateQuery(session);
    
            foreach (var result in q.Enumerable())
            {
                yield return ProjectResult(result);
            }
    
            // Commits the tnrasaction, so disposing it won't roll it back.
            session.Commit();
        }
    }