C#和#x27 ;;s使用关键字

C#和#x27 ;;s使用关键字,c#,using-statement,C#,Using Statement,我知道,每当我实例化一个实现IDisposable的类时,我都应该使用using关键字,以确保正确地处理它 像这样: using (SecureString s = new SecureString()) { } 以上内容对我来说很容易理解-我可以使用s,但是我想在这些括号内使用,但是一旦我离开这些括号,我就不能再引用s。这个范围很容易看到 但我不明白的是,当你使用没有括号的时,它是如何工作的 private void Function() { // Some code here

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

像这样:

using (SecureString s = new SecureString())
{

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

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

private void Function()
{
    // Some code here

    using (SecureString s = new SecureString())

    // more code here
}

您根本不需要使用括号。。。所以我如何知道在哪里可以使用该对象以及在哪里处置该对象,如果没有括号与
using
关键字一起使用?

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

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

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

考虑一个if语句:

if (someBool)
    DoSomething();
else
    DoSomethingElse();
这与以下内容一样有效:

if (someBool)
{
    // do lots of things
}
else
    DoSomethingElse();
using (var stream = new NetworkStream(...))
{
    using (var sslStream = new SslStream(stream))
    {
        using (var reader = new StreamReader(sslStream))
        {
            reader.WriteLine(...);
        }
    }
}
这可能在任何时候都是普遍适用的,您可以使用
{
}
括号

private void Function()
{
    // Some code here

    using (SecureString s = new SecureString())

    // more code here
}
使用
using
语句的好处在于,您可以像这样嵌套它们:

using (var stream = new NetworkStream(...))
using (var sslStream = new SslStream(stream))
using (var reader = new StreamReader(sslStream))
{
    reader.WriteLine(...);
}
这相当于以下内容:

if (someBool)
{
    // do lots of things
}
else
    DoSomethingElse();
using (var stream = new NetworkStream(...))
{
    using (var sslStream = new SslStream(stream))
    {
        using (var reader = new StreamReader(sslStream))
        {
            reader.WriteLine(...);
        }
    }
}

尽管我想你会同意它看起来漂亮多了。

要扩展其他答案:

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

// This is not.

范围基本上仅限于下一行

using(var s = new SecureString())
    s.Whatever();
s.Whatever() // ERROR! s is out of scope
这与使用不带括号的
if
关键字相同:

if(x == y)
    x = 4;

对于像
using
if
foreach
这样的语句,如果不包括括号,范围就是下一条语句(通常是下一行)。它的处理方式就像你在下一句话的括号里一样。例如

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

不带大括号的
使用
表示
使用
仅在下一条语句的范围内-与
if
条件起作用的方式相同

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

作为个人偏好,我总是使用大括号,即使对于使用
结构的单个语句
if
/
,也要使用大括号,以避免类似的混乱情况。

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

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

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

如果没有括号,只需一行即可。与“if”或“for”语句相同。
private void Function()
{
    // Some code here

    using (SecureString s = new SecureString())

    // more code here
}
例如:

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");
for(int i=0;i<10;i++)
Console.WriteLine(i.ToString());
如果(str==“你好”)
控制台。WriteLine(“您好,回来!”);
使用(SecureString s=new SecureString())
Console.WriteLine(“这里有s”);
WriteLine(“但在这里它已经超出范围”);

因为每个人都回答了这个问题,您基本上可以有一个与此等价的内联using语句:

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

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

使用
,就像
for
while
if
else
,以及其他许多关键字一样,总是将一条语句作为块的“主体”


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

查看反汇编将准确地显示正在进行的操作

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

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

     Console.WriteLine("after");
  }
使用IL disassembler,上面的函数反汇编成下面的代码。您可以看到,
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

就像没有括号的
if
for
一样。旁白:实际上,在一些边缘情况下,这样做是错误的:您可以尝试一下。通过一些简单的实验很容易弄明白…@VladimirFrolov Ohhh谢谢你。这完全有道理。我觉得现在没有意识到这一点很傻。更准确地说,这是下一句话——它可能跨越几行,甚至可能在前一行。如果该行由多个语句组成,则只有第一个语句在
using
语句中。@JonSkeet您完全正确。为了清楚起见,我更新了我的答案。如果你要投反对票,至少要有智慧来评论为什么我的答案值得投反对票。否则,我如何从我的“错误”答案中学习呢?关于如何澄清代码意图的进一步思考:并不是自动添加大括号;所有这些结构的主体总是恰好是一个语句;大括号允许您将多个语句视为单个语句。如果您已经有了一个语句,那么就不需要它们了。它不像语法明确地将大括号列为可选的。这些结构简单地说,它们后面跟着一条语句,不管该语句是什么。是的,但我觉得用我的方式来描述它更有意义,因为人们通常会这样想。哇,5分钟内10-12个正确答案回答了我的问题。我不知道该选哪个答案。我现在问这么一个明显的问题感到很傻。但我选择这一个是因为你指出了正是这种情况导致了我被欺骗