C#使用Double Idisposable的语句



我使用using

有以下语句
using (var reader = data.CreateCommand(sql).ExecuteDataReader())

在这种情况下,data是内部持有SqlConnection的某些对象。CreateCommand(sql)功能返回SqlCommandExecuteDataReader返回SqlDataReader。由于SqlCommandSqlDataReader都是IDisposable,因此是否可以通过此使用using语句来处理它们?

目前我已经这样做了:

using (var cmd = data.CreateCommand(sql))
using (var reader = cmd.ExecuteDataReader())

但是我想知道是否可以按照上述说明?

"如果可以将它们组合在一起" - 两个using完全很好,因为两者都需要处置。

您可以通过提取方法将它们结合在一起:

void RunWithReader(string sql, Action<SQLDataReader> action)
{
    using (var cmd = data.CreateCommand(sql))
    using (var reader = cmd.ExecuteDataReader())
        action(reader);
}

然后您可以使用lambda

RunWithReader("whatever command", reader =>
{
    ... // while(reader.Read() { ... } - this could also be extracted
});

同意马修·沃森(Matthew Watson)的评论。您需要两个 usings statemets。这是带有其他推理的相关问题。sqlConnection sqlcommand sqldatareader idisposable

您显示代码的方式不处理Inner IDisposableIDbCommand)。

您有两个选择:

您可以将其全部放入一个using中:

using (IDisposable cmd = data.CreateCommand(), reader = ((IDbCommand)cmd).ExecuteReader())
{
    // code here
}

但这很麻烦。另一个选项是嵌套using语句:

using (var cmd = data.CreateCommand())
{
    using (var reader = cmd.ExecuteReader())
    {
        // code here
    }
}

除此之外,您还可以有点复杂,并编写一种扩展方法来帮助(某种)为您清理。

public static class Ex
{
    public static void Using<T, R>(this T obj, Func<T, R> create, Action<T, R> use) where R : IDisposable
    {
        using (var d = create(obj))
        {
            use(obj, d);
        }
    }
}

然后您可以这样做:

data.Using(d => d.CreateCommand(), (d, c) => c.Using(c2 => c2.ExecuteReader(), (c3, r) =>
{
    // code here
}));

,但也许这并不是什么改进。

一般

您应该 Dispose 每个实现 IDisposable的类。

但是,您的问题专门处理一个方案,其中所有资源都是相关的,如果我的理解是正确的,垃圾收集器将自动为您处置这些资源。


Finalize()方法(" destructors"或" distrizers")

Finalize()方法确保在 该实例不再由应用程序引用。

Dispose() 方法

一起

Dispose()方法将"释放组件使用的所有资源"。这意味着此代码块(取自MSDN的executereader方法示例)将正确处理其使用的所有组件...

using (SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();
    SqlCommand command = new SqlCommand(queryString, connection);
    SqlDataReader reader = command.ExecuteReader();
    while (reader.Read())
    {
        // ...
    }
}

在这种情况下,处理SqlConnection时,它将正确 发布组件使用的所有资源。这意味着:

  • SqlCommand
  • SqlDataReader

    ** 注意:这一直是我的理解 ...


对以下代码进行重构:

using (SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();
    using (SqlCommand command = new SqlCommand(queryString, connection))
    {
        using (SqlDataReader reader = command.ExecuteReader())
        {
            while (reader.Read())
            {
                // ...
            }
        }
    }
}

手动处置每个资源的主要优点将是 为了获得性能增长,因为我们没有处理 Finalize方法(比使用Dispose()更昂贵。

但是,这并不意味着您要Dispose()所有内容,因为在某些情况下,Finalize()方法是一个更好的选择。


假设我到目前为止仍然处于良好状态,并且我对垃圾收集者行为的理解是有效的。

我会考虑SqlCommand(此处完整的代码参考),然后也将处置SqlReader,这意味着您可以摆脱:

using (SqlCommand command = new SqlCommand(queryString, connection))
{
    SqlDataReader reader = command.ExecuteReader();
    while (reader.Read())
    {
        // ...
    }
}

在您的情况下将转化为:

using (var cmd = data.CreateCommand(sql))
{
    var reader = cmd.ExecuteDataReader();
    // ...
}

最新更新