gpt4 book ai didi

.net - 关于使用 "using"和 "finally"清理资源

转载 作者:行者123 更新时间:2023-12-02 05:06:57 31 4
gpt4 key购买 nike

是否存在需要以下结构的情况?

using (Something something = new Something())
{
try
{
}
finally
{
something.SomeCleanup();
}
}

或者,是否应该在隐式 something.Dispose() 调用中执行所有清理任务?

<小时/>

这是有问题的代码:

public static DataTable GetDataTable(string cmdText, IEnumerable<Parameter> parameters)
{
// Create an empty memory table.
DataTable dataTable = new DataTable();

// Open a connection to the database.
using (SqlConnection connection = new SqlConnection(ConfigurationTool.ConnectionString))
{
connection.Open();

// Specify the stored procedure call and its parameters.
using (SqlCommand command = new SqlCommand(cmdText, connection))
{
command.CommandType = CommandType.StoredProcedure;

SqlParameterCollection parameterCollection = command.Parameters;
foreach (Parameter parameter in parameters)
parameterCollection.Add(parameter.SqlParameter);

try
{
// Execute the stored procedure and retrieve the results in the table.
using (SqlDataAdapter dataAdapter = new SqlDataAdapter(command))
try
{
dataAdapter.Fill(dataTable);
}
catch
{
dataTable.Dispose();
dataTable = null;
}
}
finally
{
//parameterCollection.Clear();
}
}
}

return dataTable;
}

注意:我已经定义了 Parameter 类,因此该函数的用户不必直接处理 SqlParameter 的创建。 Parameter 类的 SqlParameter 属性可用于检索 SqlParameter

在某些时候,我的程序会执行以下操作(无法发布代码,因为它涉及很多类;基本上,我有一个创建大量对象的迷你框架):

  1. 创建一个参数数组。
  2. GetDataTable('sp_one', 参数)
  3. GetDataTable('sp_two', 参数)

最佳答案

using 关键字调用 .Dispose() 方法。如果您需要在 IDisposable 对象的 dispose 方法之外进行必要的清理工作,那么您将需要在它自己的finally block 中执行此操作。这提出了两点:

  1. 此时,您可能会争辩说,您最好跳过 using block ,只在 finally block 内调用 Dispose() 。就我个人而言,我仍然会使用 using block 。 始终为您的 IDisposable 实例保留一个好习惯。
  2. 我谦虚地建议,如果您满足上述条件,则需要重新设计您的类以利用 IDisposable 模式。
<小时/>

根据您发布的代码,问题是您的参数仍然 Root 于某个地方(也许您正在重复使用它们?)。因为参数仍然是 root 的,所以无法收集。它们还包含对它们所附加的命令的引用,因此您的 SqlCommand 对象也无法立即收集,因为现在它仍然是 root 的。

关键点是.Net 框架为非托管资源保留了Dispose() 模式。由于 SqlParameters 和 SqlParameterCollection 是托管类型,因此在收集它们之前不会触及它们,而收集过程与处置完全分开。当您的 SqlCommand 最终被收集时,它的 SqlParameter 收集也将被处理。只是不要混淆收集、处置及其目的。

您想要做的是在添加每个参数时为其创建一个副本,而不是将现有参数添加到集合中。

public static DataTable GetDataTable(string cmdText, IEnumerable<Parameter> parameters)
{
// Create an empty memory table.
DataTable dataTable = new DataTable();

// Prepare a connection to the database and command to execute.
using (SqlConnection connection = new SqlConnection(ConfigurationTool.ConnectionString))
using (SqlCommand command = new SqlCommand(cmdText, connection))
{
command.CommandType = CommandType.StoredProcedure;

SqlParameterCollection parameterCollection = command.Parameters;
foreach (Parameter parameter in parameters)
parameterCollection.Add(CloneParameter(parameter.SqlParameter));

// Execute the stored procedure and retrieve the results in the table.
using (SqlDataAdapter dataAdapter = new SqlDataAdapter(command))
{
dataAdapter.Fill(dataTable);
}
}

return dataTable;
}

这里需要注意一些事情:我能够摆脱所有你的 try block 。其中一个都不需要。另外,SqlDataAdapter.Fill() 方法将为您打开和关闭连接,因此您不需要该部分。

现在我们来谈谈 CloneParameter() 函数。我的印象是,您觉得它违背了代码的目的,即尝试重用参数。我向你保证,在这里重复使用参数是一个坏主意。性能损失可以忽略不计,甚至不存在,特别是与存储过程执行相比。我将 CloneParameter() 实现留给您,有两个原因:首先它很简单,其次我们已经超出了正常的数据访问模式。我通常添加参数的做法是接受 Action 委托(delegate),而不是可枚举参数。该函数的声明方式更像是这样:

public IEnumerable<IDataRecord>GetData(string cmdText, Action<SqlParameterCollection> addParameters)

并且这样调用:

foreach(var record in GetData("myprocedurename", p => 
{
p.Add( /*new parameter here*/ );
p.Add( /*new parameter here*/ );
//...
})
.Select( /*Returning a IEnumerable rather than a datatable allows me to use it with linq to objects.*/
/* For example, you could use this spot to convert from DataRecords returned by ADO.Net to business objects */
))
{
// use the results here...
}

由于您要连续填充两个表,听起来您需要在客户端做一些工作,这可能会证明与 DataReader/IEnumerable 方法相比是合理的,但我确实想提一下这一点,因为大多数时候基于DataReader 上的代码是更好的选择。

在您的情况下,我会使用现有的基于操作委托(delegate)的模式并希望尽可能地重复使用一组重复的参数,那就是拥有一个真正的命名方法,该方法知道如何添加参数和匹配我的行动代表。然后我可以传入该方法,并重用所需的参数。

关于.net - 关于使用 "using"和 "finally"清理资源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5501446/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com