如何在异常情况下关闭DataReader

7

我在我的数据层的一些方法中有以下代码:

StringBuilder sb = new StringBuilder();
SqlCommand s = new SqlCommand(sb.ToString(), conn);
try 
{ 
    SqlDataReader dr = s.ExecuteReader(); 
    while(dr.Read())
      DoSomething(dr);
}
catch (Exception ex)
{ 
    sb.Append(Util.ExceptionRecursive(ex)); 
}

问题在于,出现异常时DataReader 不会关闭。当其他方法试图访问另一个DataReader 时,它会抛出另一个异常,提示“另一个DataReader 已连接到数据库”。

我希望无论什么情况下都能关闭我的DataReader。 但是这样做:

sb = new StringBuilder();
SqlCommand s = new SqlCommand(sb.ToString(), conn);
SqlDataReader dr;
try 
{
    dr = s.ExecuteReader(); 
    while(dr.Read())
      DoSomething(dr);
}
catch (Exception ex)
{ 
    sb.Append(Util.ExceptionRecursive(ex)); 
}
finally
{
    dr.Close();
}

这样做行不通,因为在异常情况下,可能没有数据可用,而且无法编译。

那我该怎么办呢?


如果你正在构建连接字符串,应该使用 ConnectionStringBuilder - SLaks
1
@Lasse:关于连接字符串。(我以为他也在创建一个 SqlConnection) - SLaks
你应该使用参数。 - SLaks
conn是一个已经创建好的SqlConnection。 - apacay
3个回答

12

您应该使用using语句
它会生成一个finally块,以确保您的资源始终被释放。

StringBuilder sb = new StringBuilder();
using (SqlCommand s = new SqlCommand(sb.ToString(), conn)) {
    try 
    { 

        using (SqlDataReader dr = s.ExecuteReader()) {
            while(dr.Read())
              DoSomething(dr);
        }

    }
    catch (Exception ex)
    { 
        sb.Append(Util.ExceptionRecursive(ex)); 
    }    
}

使用 using 关键字会发生什么?是释放还是关闭?如果是释放,它会“记得”关闭 DataReader 吗? - apacay
2
@apacay:Dispose() 调用 Close()。你应该为每个对象使用单独的 using 语句。 - SLaks

4
最好的方法可能是这样的:
sb = new StringBuilder();
...
using (SqlCommand s = new SqlCommand(sb.ToString(), conn))
using (SqlDataReader dr = s.ExecuteReader())
{
    try
    {
        while(dr.Read())
          DoSomething(dr);
    }
    catch (Exception ex)
    { 
        sb.Append(Util.ExceptionRecursive(ex)); 
    }
}

然而,如果您期望在SQL执行期间出现异常(或不出现异常),则必须将异常处理代码放在外部:

sb = new StringBuilder();
...
try
{
    using (SqlCommand s = new SqlCommand(sb.ToString(), conn))
    using (SqlDataReader dr = s.ExecuteReader())
    {
        while(dr.Read())
          DoSomething(dr);
    }
}
catch (Exception ex)
{ 
    sb.Append(Util.ExceptionRecursive(ex)); 
}

但这完全取决于您期望异常出现的位置。 - Lasse V. Karlsen
异常通常来自于ExecuteReader,而不是Read - SLaks
他们可能来自于DoSomething,但我同意,修改了答案。 - Lasse V. Karlsen
@Lasse 我的问题来自于 ExecuteReader... DoSomething(SqlDataReader dr) 不应该引起任何麻烦。 - apacay

0
你可以这样写:
if(dr!=null) dr.Close();

我曾考虑过这个,但对我来说似乎不太干净。 - apacay

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接