C#中匿名未附加块的价值是多少?

在C#中,您可以在未附加到任何其他语句的方法中创建块。

public void TestMethod() { { string x = "test"; string y = x; { int z = 42; int zz = z; } } } 

此代码编译并运行,就像主方法中的大括号不在那里一样。 还要注意块内部的块。

有没有这种情况有价值? 我还没有找到,但我很想知道其他人的发现。

范围和垃圾收集:当您离开未连接的块时,其中声明的任何变量都超出范围。 这让垃圾收集器可以清理这些对象。

Ray Hayes指出.NET垃圾收集器不会立即收集超出范围的对象,因此范围界定是主要的好处。

一个例子是如果你想重用一个变量名,通常你不能重用变量名这是无效的

  int a = 10; Console.WriteLine(a); int a = 20; Console.WriteLine(a); 

但这是:

  { int a = 10; Console.WriteLine(a); } { int a = 20; Console.WriteLine(a); } 

我现在唯一能想到的就是,例如,如果你正在处理一些大型对象,并从中提取出一些信息,之后你将执行一系列操作,你可以把大对象处理掉在块中,使其超出范围,然后继续其他操作

  { //Process a large object and extract some data } //large object is out of scope here and will be garbage collected, //you can now perform other operations with the extracted data that can take a long time, //without holding the large object in memory //do processing with extracted data 

它是解析器规则的副产品,该语句是简单语句或块。 即,只要单个语句可以使用块。

例如

 if (someCondition) SimpleStatement(); if (SomeCondition) { BlockOfStatements(); } 

其他人指出变量声明在范围内,直到包含块结束。 临时变量具有短范围是有好处的,但我从来不必使用它自己的块来限制变量的范围。 有时你会在“using”语句下面使用一个块。

所以一般来说它没有价值。

据我所知,从组织的角度来看,这只是有用的。 我无法真正想到这样做的任何逻辑价值。 也许有人会有一个恰当的例子。

这允许您在任何地方创建范围块。 它本身并没有那么有用,但可以使逻辑变得更简单:

 switch( value ) { case const1: int i = GetValueSomeHow(); //do something return i.ToString(); case const2: int i = GetADifferentValue(); //this will throw an exception - i is already declared ... 

在C#中,我们可以使用范围块,以便在每种情况下声明的项目仅在范围内:

 switch( value ) { case const1: { int i = GetValueSomeHow(); //do something return i.ToString(); } case const2: { int i = GetADifferentValue(); //no exception now return SomeFunctionOfInt( i ); } ... 

这也适用于gotos和标签,而不是你经常在C#中使用它们。

它存在的一个实际原因是,如果你想要在没有引人注目的需要引入块的任何其他原因时限制某些变量的范围。 在实际操作中,这实际上从未有用。

就个人而言,我的猜测是,从语言/编译器的角度来看,更容易说你可以把一个块放在预期的语句的任何地方,而且他们根本就没有尽力阻止你在没有if的情况下使用它。 / for / method declaration / etc.

从Eric Lippert 最近的博客文章开始考虑。 if语句后面没有单个语句或大括号括起来的一些语句,后面只跟一个语句。 无论何时用花括号括起0到N个语句,你都要使那段代码等同于(从语言分析器的角度来看)一个语句。 同样的做法也适用于所有循环结构,尽管正如博客文章的主要内容所解释的那样,它不适用于try / catch / finally块。

当从这个角度解决块时,问题就变成了,“是否有令人信服的理由阻止在任何可以使用单个语句的地方使用块?” 答案是“不”。

这样做的一个原因是变量’z’和’zz’不能用于该内部块末尾下面的代码。 当您在Java中执行此操作时,JVM会为内部代码推送堆栈帧,并且这些值可以存在于堆栈中。 当代码退出块时,会弹出堆栈帧并且这些值消失。 根据所涉及的类型,这可以使您不必使用堆和/或垃圾回收。

在C#中 – 像c / c ++ / java – braces表示范围。 这决定了变量的生命周期。 当到达右括号时,变量立即可用于垃圾收集。 在c ++中,如果var表示一个实例,它将导致调用类的析构函数。

至于用法,唯一可能的用途是释放一个大对象但是tbh,将它设置为null会产生相同的效果。 我怀疑之前的用法可能只是为了让c ++程序员在熟悉和舒适的领域中转向托管代码。 如果真的想在c#中调用“析构函数”,通常会实现IDisposable接口并使用“using(var){…}”模式。

[287]莪

即使它实际上对任何原因都有用(例如变量范围控制),但从良好的旧代码可读性的角度来看,我会劝阻你不要使用这种结构。

除了语义以及范围和垃圾收集之外,没有任何其他值,在这个有限的例子中没有一个是重要的。 如果您认为它使代码更清晰,对于您自己和/或其他人来说,那么您当然可以使用它。 但是,代码中更为公认的语义澄清约定通常只使用选项内联注释换行符:

 public void TestMethod() { //do something with some strings string x = "test"; string y = x; //do something else with some ints int z = 42; int zz = z; }