繁体   English   中英

C#使用带有双重IDisposable的语句

[英]c# using statement with double IDisposable

我有以下using语句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())

但是我想知道是否可以如上所述将它们组合在一起?

同意Matthew Watson的评论。 您需要同时usings usestatemets。 这是带有其他推理的相关问题。 SqlConnection SqlCommand SqlDataReader IDisposable

“如果有可能将它们组合在一起” -两种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
});

内部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()方法(“析构函数”或“终结器”)

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()

但是,这并不意味着您想全部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(); // ... } 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM