对于指向一个IDisposable的所有变量,一个using语句是否足够?
本文关键字:一个 using 变量 语句 是否 于指 IDisposable | 更新日期: 2023-09-27 18:19:18
例如so:在方法中创建它并将其分配给一个字段。将该字段传递给方法,然后将其分配给using语句的变量(这是唯一被调用的Dispose
)。
SqlCommand CreateSqlCommand()
{
SqlCommand cmd1 = new SqlCommand();
return cmd1;
}
void UseSqlCommand(SqlCommand cmd4)
{
using (SqlCommand cmd3 = cmd4)//Is this using-statement enough?
{
//use cmd3 here...
}
}
和使用:
SqlCommand cmd2 = CreateSqlCommand();
UseSqlCommand(cmd2);
额外细节: GC是否在下一轮收集所有这些变量?为什么不呢——请看David M. Kean的回答。
编辑
我会增加
cmd2.CommandText = "";
在前一行(最后一行)之后。并且没有抛出错误。
为什么?应该已经处理掉了!没关系。被处置的对象可以被引用…
请不要把注意力集中在例子上,而是集中在问题本身上。谢谢。
是的,using语句将在引用变量的块完成后调用Dispose()。这是一件好事,也是一件坏事,假设您创建了一个sql命令并将结果存储在变量cmd
中,然后将该变量传递给使用和处置cmd
的另一个方法。现在您遇到了一个已被处理的变量,如果您尝试使用它,它可能会抛出一个ObjectDisposedException
。
SqlCommand cmd = CreateSqlCommand();
UseSqlCommand(cmd);
//Uh oh, cmd can still be used, what if I tried to call UseSqlCommand(cmd) again?
在方法之外处理该对象会更清晰和安全(如jord
using(SqlCommand cmd = CreateSqlCommand())
{
UseSqlCommand(cmd);
}
现在你可以完全控制对象并限制它的作用域。
从外部控制using
的作用域:
using (SqlCommand cmd2 = CreateSqlCommand()) {
UseSqlCommand(cmd2);
}
...
void UseSqlCommand(SqlCommand cmd4) {
// use cmd4 here...
}
或者将UseSqlCommand
重命名为其他的东西,比如ExecuteSqlCommand
。
using
语句的目的不是处理变量,而是处理对象实例。变量通常用于标识对象实例,但是引用类型变量不包含对象——它们包含"对象标识符"。
如果有人说,例如var myPort = new System.Io.Ports.SerialPort("COM1", ...); myPort.Open()
, SerialPort
对象将要求系统让它使用COM1
串行端口,并且不让其他任何人使用它,直到进一步通知。系统将为该端口生成句柄,并设置一些标志,以便只有具有该句柄的代码才被允许使用该端口。一旦对象被创建(假设系统任意地为它分配了一个ID #8675309),系统将把这个ID存储到变量myPort
中。
当代码不再需要使用该串行端口时,重要的是有人告诉对象#8675309不再需要它,因此它可以反过来告诉系统它应该使COM1可供其他应用程序使用。这通常是通过在包含对象#8675309引用的变量上调用Dispose
来实现的。一旦完成,每个包含对对象#8675309引用的变量都将包含对其Dispose
方法已被调用的对象的引用。请注意,Dispose
方法实际上不会影响这些变量中的任何一个(除非在方法本身的代码中重写它们)。在调用之前持有"object# 8675309"的任何变量将在调用之后继续持有。对象将释放其串行端口,因此存储这些变量的引用将不再有用,并且使用这些变量的代码可能希望它们被清除,但是SerialPort
对象不会以这种或那种方式关心。
我认为这就是你想要做的:
public class MySqlClass : IDisposable
{
private SqlConnection conn { get; set; }
public MySqlClass(string connectionstring)
{
conn = new SqlConnection(connectionstring);
}
public void DoSomething1(string tsql)
{
using (SqlCommand comm = new SqlCommand(tsql, conn)) {
conn.Open();
}
}
public void DoSomething2(string tsql)
{
using (SqlCommand comm = new SqlCommand(tsql, conn)) {
conn.Open();
}
}
//DISPOSE STUFF HERE
}
使用……
using (MySqlClass MySQL = new MySqlClass())
{
MySQL.DoSomething1();
MySQL.DoSomething2();
}
* UPDATE *更新>>>>示例<<<<关键是您创建了上述SqlConnection的单个实例,并且可以重用它。该类实现了IDisposable,因此您可以使用using()方法来自动处置。