在C#中的“using”语句中使用各种类型

29

既然C#的using语句只是try/finally{dispose}的语法糖,为什么它只接受多个相同类型的对象作为参数呢?

我不明白,因为它们只需要实现IDisposable接口就可以,如果它们都实现了IDisposable,那应该没问题,但事实并非如此。

具体来说,我习惯于编写以下代码:

using (var cmd = new SqlCommand())
{
    using (cmd.Connection)
    {
        // Code
    }
}

我压缩成:

using (var cmd = new SqlCommand())
using (cmd.Connection)
{
    // Code
}

我想进一步压缩为:

using(var cmd = new SqlCommand(), var con = cmd.Connection)
{
    // Code
}

但我不行。一些人可能会说,我可以写:

using((var cmd = new SqlCommand()).Connection)
{
    // Code
}

因为我只需要处理连接而不是命令,但这并不重要。


我认为这实际上是一个好主意。我认为这只是还没有被实现的东西。如果真的没有特定的原因,这个不存在会让我感到惊讶。不过我可能错了... - BFree
2
我在这里学到了新东西吗?顶部示例中的第二个未分配的使用语句是什么意思?那个项目变成了作用域吗? - spender
@spender:使用的参数需要是可以转换为IDisposable的表达式。声明就是这样一个表达式。 - H H
@spender:是的,你(可能)学到了新东西。使用 IDisposable 实例的语法是 using(IDisposableInstance) 语句;正如 Henk Holterman 所说的,赋值是一种操作,其结果(通常未使用但在此处使用)是分配的值。 - Andrei Rînea
1
受到你的问题启发,我尝试了以下想法:http://stackoverflow.com/questions/974484/captured-variable-instantiating-problem/ - VVS
显示剩余3条评论
4个回答

21
你可以这样做:
using (IDisposable cmd = new SqlCommand(), con = (cmd as SqlCommand).Connection)
{
   var command = (cmd as SqlCommand);
   var connection = (con as SqlConnection);
   //code
}
也许那对你来说很令人满意。

这是我迄今为止看到的最接近的解决方法。但是,在块中需要将 cmd 强制转换回 SqlCommand 才能操纵它。同样的,"con" 也需要打开以完成我的工作。 - Andrei Rînea
@Andrei 你说得对,我会更新我的回答来反映你所说的内容。 - Joseph
这正是我所说的。我认为这并不比使用() using () { }版本更好。 - H H
是的,如果你以后必须要将这些东西转换回来,那么这比只将其分成两行更糟糕。 - mqp
1
@Henk 哦,我明白了。我同意。我自己也更喜欢使用堆叠的using语句。我只是在回答他如何做到他想做的事情的问题。 - Joseph
@Joseph,显然这是一种可怕的技术,正如你所承认的那样,但无疑这是一个非常巧妙的代码片段! - RichardOD

17

其实并没有非常好的技术原因;我们本可以设计一种语法,允许声明多个不同类型的变量。但既然我们没有这样做,而且已经有了一种完美的、清晰易懂、相当简洁的机制来声明不同类型的嵌套使用块,我们不太可能再添加新的语法糖,仅仅为了节省一些按键。


12
我了解了……为了防止语法糖过量导致“语法糖糖尿病”,我们将不再添加任何语法糖 :P - Andrei Rînea
句法糖尿病.. muahah :) - VVS
2
换句话说,呃! 耸肩 - Maxim Gershkovich
2
但是等等,C# 中有很多东西可以“节省一些按键”。结合起来,它们可以节省很多按键。越多越好!MSIL + 糖 = C#。 - Camilo Martin
除了这就是语法糖的全部意义——节省击键并使事情更容易阅读。 - d512

5

C#中的其他变量声明只允许您在同一语句中声明多个相同类型的变量;我不明白为什么using头文件应该不同。


是的和不是的。没有任何阻止您执行:IComparable c1, c2;,然后在代码中稍后使c1和c2成为完全不同的实现IComparable的具体类型。这就是OP指出的问题,他们只需要是IDisposable... - BFree
当然可以,但你也可以使用IDisposable在using语句中实现,例如:using (IDisposable a = new SqlCommand(), b = new SqlConnection())。 - mqp
BFree,这正是mquander所说的,不是吗?使用(IDisposable x = new Connection(),y = new Command())会起作用,但没有什么用处。引用类型计数。 - H H

0

我的个人做法或许能够满足你的需求:

private const string SQL_CONNECTION = "Your Connection String Here";

private void Test(string sqlCmd)
{
  using (var cmd = new SqlCommand(sqlCmd, new SqlConnection(SQL_CONNECTION)))
  {
    cmd.Connection.Open();
    cmd.ExecuteNonQuery();
    cmd.Connection.Close();
    // Close() is not really necessary.
    // Dispose will Close the connection.
  }
}

不,这不是在一行中使用using语句的两个实例,但它和你在示例中试图获得的紧凑程度一样。

此外,您可以通过将连接字符串转换为私有属性,使其更加紧凑和程序员友好:

private SqlConnection OpenConnection
{
  get {
    var con = new SqlConnection(SQL_CONNECTION);
    con.Open();
    return con;
  }
}

现在,上面在Test()中的第一段代码可以缩短为以下内容:

private void Test2(string sqlCmd)
{
  using (var cmd = new SqlCommand(sqlCmd, OpenConnection))
  {
    cmd.ExecuteNonQuery();
  }
}

这使编程变得非常愉快。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接