Reputation: 9756
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?
Upvotes: 2
Views: 294
Reputation: 36573
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;
}
Upvotes: 5