5

I understand that any time I am instantiating a class that implements IDisposable, I should use the using keyword in order to ensure that it's disposed of properly.

Like so:

using (SecureString s = new SecureString())
{

}

The above is easy for me to understand - I can use s however I want within those brackets, but once I leave those brackets, I can no longer refer to s. The scope is easy to see.

But what I don't understand is how it works when you use using with no enclosing brackets.

private void Function()
{
    // Some code here

    using (SecureString s = new SecureString())

    // more code here
}

You aren't required to use brackets at all... so... how do I know where I am able to use the object and where it gets disposed, if there are no brackets to go with the using keyword?

4

12 回答 12

8

在 C# 中几乎所有情况下,当您可以选择使用大括号时,您都可以用一行代码替换它们。

考虑一个 if 语句:

if (someBool)
    DoSomething();
else
    DoSomethingElse();

这与以下内容一样有效:

if (someBool)
{
    // do lots of things
}
else
    DoSomethingElse();

{任何时候你都可以使用和}括号,这可能几乎是普遍适用的。

这个using语句的好处是你可以像这样嵌套它们:

using (var stream = new NetworkStream(...))
using (var sslStream = new SslStream(stream))
using (var reader = new StreamReader(sslStream))
{
    reader.WriteLine(...);
}

这等效于以下内容:

using (var stream = new NetworkStream(...))
{
    using (var sslStream = new SslStream(stream))
    {
        using (var reader = new StreamReader(sslStream))
        {
            reader.WriteLine(...);
        }
    }
}

虽然我认为你会同意它看起来更好看。

于 2013-10-17T14:23:08.950 回答
6

using不带大括号的A表示using在下一条语句的范围内- 与条件的工作方式相同。if

using (SecureString s = new SecureString())
    s.Foo(); // Works
s.Foo(); // out of scope

作为个人喜好,我总是包含大括号,即使是单个语句if/using构造,以避免像这样的混乱情况。

于 2013-10-17T14:23:52.033 回答
3

然后在 using 语句之后的下一条命令中有效。

请注意,这并不意味着下一行。只有下一个命令

于 2013-10-17T14:22:10.293 回答
2

正如每个人都回答的那样,您基本上可以拥有一个与此等效的内联 using 语句:

using(var s = new SecureString()) s.Whatever();

但是请不要这样做,因为我认为您会降低代码的可读性并使其他开发人员感到困惑。我认为您提出这个问题的事实很好地说明了这一点。

于 2013-10-17T14:27:41.193 回答
2

范围基本上限于下一行。

using(var s = new SecureString())
    s.Whatever();
s.Whatever() // ERROR! s is out of scope

if这与使用不带括号的关键字相同:

if(x == y)
    x = 4;
于 2013-10-17T14:23:38.723 回答
2

对于, 和等语句using,如果不包含括号,则范围只是下一条语句(通常是下一行)。就像您在下一条语句周围包含括号一样对待它。例如ifforeach

if (someCondition)
    Console.WriteLine("someCondition is true!");
Console.WriteLine("I run regardless");
// same as
if (someCondition)
{
    Console.WriteLine("someCondition is true!");
}

using (var s = new SecureString())
    Console.WriteLine(s); // this works!
//Console.WriteLine(s); // s is no longer in scope, this won't compile
于 2013-10-17T14:23:47.567 回答
1

要扩展其他答案:

using (SecureString s = new SecureString())
    // This statement is in using scope.

// This is not.
于 2013-10-17T14:23:18.373 回答
1

如果不使用括号,则只有下一条语句有效

using (SecureString s = new SecureString())
    // statement here

如果要包含多个语句,请使用括号。

于 2013-10-17T14:23:53.667 回答
1

如果没有括号,你只会得到一行。与“if”或“for”语句相同。例如:

for (int i = 0; i < 10; i++)
    Console.WriteLine(i.ToString());

if (str == "hello")
    Console.WriteLine("hello back!");

using (SecureString s = new SecureString())
    Console.WriteLine("Here we have s");

Console.WriteLine("but here it's out of scope already");
于 2013-10-17T14:24:18.360 回答
0

查看反汇编将告诉您到底发生了什么。

  static private void Function()
  {
     Console.WriteLine("before");

     using (SecureString s = new SecureString())
        s.Clear();

     Console.WriteLine("after");
  }

使用IL Dissassembler,上面的函数反汇编为下面的代码。您可以看到该using语句是通过try-finally包装语句的其余部分来实现的(可以是由花括号定义的块,但在这种情况下只是分号)。您正在使用的对象被放置在finally块中。然后,在 之外finally,代码继续执行源代码中的下一条语句。

.method private hidebysig static void  Function() cil managed
{
  // Code size       56 (0x38)
  .maxstack  2
  .locals init ([0] class [mscorlib]System.Security.SecureString s,
           [1] bool CS$4$0000)
  IL_0000:  nop
  IL_0001:  ldstr      "before"
  IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_000b:  nop
  IL_000c:  newobj     instance void [mscorlib]System.Security.SecureString::.ctor()
  IL_0011:  stloc.0
  .try
  {
    IL_0012:  ldloc.0
    IL_0013:  callvirt   instance void [mscorlib]System.Security.SecureString::Clear()
    IL_0018:  nop
    IL_0019:  leave.s    IL_002b
  }  // end .try
  finally
  {
    IL_001b:  ldloc.0
    IL_001c:  ldnull
    IL_001d:  ceq
    IL_001f:  stloc.1
    IL_0020:  ldloc.1
    IL_0021:  brtrue.s   IL_002a
    IL_0023:  ldloc.0
    IL_0024:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
    IL_0029:  nop
    IL_002a:  endfinally
  }  // end handler
  IL_002b:  nop
  IL_002c:  ldstr      "after"
  IL_0031:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0036:  nop
  IL_0037:  ret
} // end of method Program::Function
于 2013-10-17T14:36:27.860 回答
0

using,就像for, while, if, else, 和许多其他关键字一样,总是将一个语句作为块的“主体”。

如果程序员想在主体内执行多个语句,他们可以使用花括号来创建一个复杂的语句,即执行多个(或零个)语句的单个语句。using当您在 a或之后使用花括号时,if您是在说“这里的所有内容都应该被视为一个语句”。如果您已经有一个语句开头,则无需使用大括号将其转换为单个语句,因此您可以省略它们。

于 2013-10-17T14:32:55.140 回答
0

正如其他评论中提到的,当你提到的方式使用 using 语句时,只有当你有一行时。

我想补充一点,C# 8.0您可以通过这种方式使用“使用声明”

private void Function()
{
    // Some code here

    using SecureString s = new SecureString();

    // more code here
}

这样,using语句的生命周期将延长到声明它的范围的末尾。然后using将按照声明它们的相反顺序处理本地人。

于 2021-07-16T12:48:44.033 回答