Search code examples
.netdelegatesusing-statementdeferred-execution

Returning IEnumerable with using


Interesting problem I ran across which makes total sense. I have a generic method like so:

public TResult Run<TResult>(Func<SqlDataReader, TResult> resultDelegate)
{
   TResult result;

   using (SqlDataReader reader = command.ExecuteReader()) // command is SqlCommand with attached SqlConnection
   {
      result = resultsDelegate(reader);
   }

   // Some other unrelated code (but that's why result has a variable)

   return result;
}

In one case, the resultDelegate's return type (TResult) is IEnumerable<object>. The problem is that the Run function returns immediately due to deferred execution, disposing the SqlDataReader. Later in the code when I try to read through the results (which the delegate does reader.Read(), I get an InvalidOperationException: Invalid attempt to call Read when reader is closed.

I'm having a hard time figuring out the best way around this. I know I can return a concrete list, but I would like to avoid that if possible. I can also move the using statement inside the delegate, but once again, if I can avoid doing that for every delegate it would be nice. Any ideas?


Solution

  • Perhaps:

    public TResult Run<TResult>(Func<SqlDataReader, TResult> resultDelegate)
    {
       TResult result;
    
       using (SqlDataReader reader = command.ExecuteReader()) // command is SqlCommand with attached SqlConnection
       {
          result = resultsDelegate(reader);
          if (typeof(TResult) == typeof(IEnumerable<object>)) 
          {
             var enumerable = result as IEnumerable<object>;
             if (enumerable != null) 
             {
                result = enumerable.ToList();  
             }
          }
       }
    
       // Some other unrelated code (but that's why result has a variable)
    
       return result;
    
    }