c# using 语句 with double IDisposable
c# using statement with double IDisposable
我有以下使用 using
的语句:
using (var reader = data.CreateCommand(sql).ExecuteDataReader())
在这种情况下 data
是内部保存 SqlConnection
的某个对象。 CreateCommand(sql)
函数 returns SqlCommand
和 ExecuteDataReader
returns SqlDataReader
。由于 SqlCommand
和 SqlDataReader
都是 IDisposable
,因此使用 using
语句会同时处理它们吗?
目前我是这样做的:
using (var cmd = data.CreateCommand(sql))
using (var reader = cmd.ExecuteDataReader())
但我想知道是否可以按照上述方式将它们组合起来?
同意 Matthew Watson 的评论。您需要同时拥有 usings
个状态。
这是带有附加推理的相关问题。 SqlConnection SqlCommand SqlDataReader IDisposable
"if it's possible to combine them" - 两个 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
});
您在内部 IDisposable
(IDbCommand
) 中呈现代码的方式未被处理。
你有两个选择:
你可以像这样把它们全部放在一个 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
}));
但也许这并没有太大的改善。
一般
You should Dispose
every class that implements IDisposable
.
但是,你的问题是专门处理一个场景所有资源都是相关的,如果我的理解是正确的,垃圾收集器会自动为你处理这些资源.
Finalize()
方法("Destructors" 或 "Finalizers")
The Finalize()
method makes sure that resources are disposed when
the instance is no longer referenced by the application.
配合Dispose()
方法
Dispose()
方法将 "release all resources used by the component"。这意味着此代码块(取自 MSDN's ExecuteReader Method Example)将正确处理它使用的所有组件...
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlCommand command = new SqlCommand(queryString, connection);
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
// ...
}
}
In this case, when disposing SqlConnection
, it will properly
release all resources used by the component. Which means:
SqlCommand
SqlDataReader
** Note: This has always been my understanding...
将上述代码重构为以下代码:
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
using (SqlCommand command = new SqlCommand(queryString, connection))
{
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
// ...
}
}
}
}
The main advantage of manually disposing of each resource, would be
for a performance gain since we are not processing up to the
Finalize
method (which is relatively a more expensive than doing Dispose()
.
但是,这并不意味着您想要 Dispose()
一切,因为在某些情况下 Finalize()
方法是更好的选择。
假设到目前为止我仍然处于良好状态,并且我对垃圾收集器行为的理解是有效的。
我会考虑 SqlCommand
(完整代码参考 here),然后也会处理 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();
// ...
}
我有以下使用 using
的语句:
using (var reader = data.CreateCommand(sql).ExecuteDataReader())
在这种情况下 data
是内部保存 SqlConnection
的某个对象。 CreateCommand(sql)
函数 returns SqlCommand
和 ExecuteDataReader
returns SqlDataReader
。由于 SqlCommand
和 SqlDataReader
都是 IDisposable
,因此使用 using
语句会同时处理它们吗?
目前我是这样做的:
using (var cmd = data.CreateCommand(sql))
using (var reader = cmd.ExecuteDataReader())
但我想知道是否可以按照上述方式将它们组合起来?
同意 Matthew Watson 的评论。您需要同时拥有 usings
个状态。
这是带有附加推理的相关问题。 SqlConnection SqlCommand SqlDataReader IDisposable
"if it's possible to combine them" - 两个 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
});
您在内部 IDisposable
(IDbCommand
) 中呈现代码的方式未被处理。
你有两个选择:
你可以像这样把它们全部放在一个 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
}));
但也许这并没有太大的改善。
一般
You should
Dispose
every class that implementsIDisposable
.
但是,你的问题是专门处理一个场景所有资源都是相关的,如果我的理解是正确的,垃圾收集器会自动为你处理这些资源.
Finalize()
方法("Destructors" 或 "Finalizers")
The
Finalize()
method makes sure that resources are disposed when the instance is no longer referenced by the application.
配合Dispose()
方法
Dispose()
方法将 "release all resources used by the component"。这意味着此代码块(取自 MSDN's ExecuteReader Method Example)将正确处理它使用的所有组件...
using (SqlConnection connection = new SqlConnection(connectionString)) { connection.Open(); SqlCommand command = new SqlCommand(queryString, connection); SqlDataReader reader = command.ExecuteReader(); while (reader.Read()) { // ... } }
In this case, when disposing
SqlConnection
, it will properly release all resources used by the component. Which means:
SqlCommand
SqlDataReader
** Note: This has always been my understanding...
将上述代码重构为以下代码:
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
using (SqlCommand command = new SqlCommand(queryString, connection))
{
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
// ...
}
}
}
}
The main advantage of manually disposing of each resource, would be for a performance gain since we are not processing up to the
Finalize
method (which is relatively a more expensive than doingDispose()
.
但是,这并不意味着您想要 Dispose()
一切,因为在某些情况下 Finalize()
方法是更好的选择。
假设到目前为止我仍然处于良好状态,并且我对垃圾收集器行为的理解是有效的。
我会考虑 SqlCommand
(完整代码参考 here),然后也会处理 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(); // ... }