C#使用关键字的范围

时间:2013-10-17 14:20:43

标签: c# using-statement

据我所知,每当我实例化一个实现IDisposable的类时,我都应该使用using关键字,以确保它被正确处理。

像这样:

using (SecureString s = new SecureString())
{

}

以上内容对我来说很容易理解 - 我可以使用s但我希望在这些括号内,但是一旦我离开这些括号,我就不能再引用s了。范围很容易看到。

但我不明白的是当你使用using没有括号时它是如何工作的。

private void Function()
{
    // Some code here

    using (SecureString s = new SecureString())

    // more code here
}

你根本不需要使用括号......所以...如果没有括号可以使用{{1,我怎么知道我能够在哪里使用该对象以及它在何处被处置关键字?

12 个答案:

答案 0 :(得分: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(...);
        }
    }
}

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

答案 1 :(得分:6)

没有大括号的using表示using仅在 的下一个语句的范围内 - 与if条件的工作方式相同。

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

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

答案 2 :(得分:3)

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

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

答案 3 :(得分:2)

范围基本上限于下一行。

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

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

if(x == y)
    x = 4;

答案 4 :(得分:2)

使用usingifforeach等语句,如果不包含括号,则范围只是下一个语句(通常是下一行)。它就像你在下一个声明中包括括号一样对待。 E.g。

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

答案 5 :(得分:2)

正如大家都回答的那样,你基本上可以使用与此相同的内联使用语句:

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

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

答案 6 :(得分:1)

扩展其他答案:

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

// This is not.

答案 7 :(得分:1)

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

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

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

答案 8 :(得分: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");

答案 9 :(得分:0)

using,就像forwhileifelse以及许多其他关键字一样,只需要一个语句作为“正文” “块。

如果程序员想要在正文中执行多个语句,他们可以使用花括号来创建复杂语句,即执行多个(或零)语句的单个语句。当您在usingif之后使用花括号时,“此处的所有内容都应视为一个语句”。如果您已经开始使用完全一个语句,则无需使用大括号将其转换为单个语句,因此您可以省略它们。

答案 10 :(得分: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

答案 11 :(得分:0)

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

我想在 C# 8.0 中添加,您可以这样使用 "using declarations"

private void Function()
{
    // Some code here

    using SecureString s = new SecureString();

    // more code here
}

这样,using 语句的生命周期将延伸到声明它的作用域的末尾。然后,using 局部变量将按照与声明它们的相反顺序进行处理。