对于指向一个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 = "";

在前一行(最后一行)之后。并且没有抛出错误。

为什么?应该已经处理掉了!没关系。被处置的对象可以被引用…

请不要把注意力集中在例子上,而是集中在问题本身上。谢谢。

对于指向一个IDisposable的所有变量,一个using语句是否足够?

是的,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()方法来自动处置。