Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/321.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#中匿名未附加块的值是多少?_C# - Fatal编程技术网

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

C#中匿名未附加块的值是多少?,c#,C#,在C#中,您可以在方法内部生成一个块,而该块不附加到任何其他语句 public void TestMethod() { { string x = "test"; string y = x; { int z = 42; int zz = z; } } } 这段代码的编译和运行就像主

在C#中,您可以在方法内部生成一个块,而该块不附加到任何其他语句

    public void TestMethod()
    {
        {
            string x = "test";
            string y = x;

            {
                int z = 42;
                int zz = z;
            }
        }
    }
这段代码的编译和运行就像主方法中的大括号不存在一样。还要注意块内部的块


是否存在这样一种情况,即这将是有价值的?我还没有发现,但我很想听听其他人的发现。

据我所知,这只会从组织的角度看有用。我真的无法想象这样做有什么逻辑价值。也许有人会有一个合适的例子。

作用域和垃圾收集:当您离开未附加的块时,其中声明的任何变量都超出了作用域。这样垃圾收集器就可以清理这些对象


指出.NET垃圾收集器不会立即收集范围外对象,因此作用域是主要的好处

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

这是解析器规则的副产品,即语句是简单语句或块。i、 e.一个块可以在任何可以使用单个语句的地方使用

e、 g

其他人指出,变量声明在包含块结束之前都在作用域中。临时变量有一个短的作用域是好的,但是我从来没有使用过一个单独的块来限制变量的作用域。有时,您会在“using”语句下面使用一个块

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

在C#中——就像C/C++/java一样——大括号表示范围。这决定了变量的生存期。当到达右大括号时,变量立即可用于垃圾回收。在C++中,如果var表示实例,则会调用类的析构函数。p> 至于用法,唯一可能的用法是释放一个大对象,但是tbh,将其设置为null将具有相同的效果。我怀疑前者的用法可能只是为了让C++程序员在熟悉和舒适的领域中移动到托管代码。如果真的想在c#中调用“析构函数”,通常实现IDisposable接口并使用“using(var){…}”模式


Oisin

即使它因任何原因(例如变量作用域控制)实际上是有用的,但从良好的旧代码可读性的角度来看,我不鼓励您使用这种构造。

除了语义、作用域和垃圾收集之外,没有其他价值,在这个有限的示例中,这些都不重要。如果你认为它能让你自己和/或他人的代码更清晰,那么你当然可以使用它。然而,代码中语义澄清的更为普遍接受的约定通常仅在选项行内注释中使用换行符:

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;
}

例如,如果您想重用变量名,通常不能重用变量名 这是无效的

        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

这允许您在任何位置创建范围块。它本身没有多大用处,但可以简化逻辑:

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 );
    }
 ...

这也适用于GOTO和标签,这不是因为您经常在C#中使用它们。

它存在的一个实际原因是,如果您想在不需要引入任何其他阻塞原因的情况下限制某些变量的范围。在实际操作中,这几乎没有任何用处

就我个人而言,我的猜测是,从语言/编译器的角度来看,可以更容易地说,您可以将一个块放在任何需要语句的地方,而它们只是没有特意阻止您在没有if/for/method声明的情况下使用它

以Eric Lippert的开头为例。
如果一个
语句后面没有一个语句或多个用大括号括起来的语句,那么它后面就是一个语句。无论何时,只要将0到N条语句用大括号括起来,就可以使代码的这一部分等价(从语言解析器的角度来看)成为一条语句。同样的做法也适用于所有循环结构,尽管正如博文的要点所解释的,它不适用于try/catch/finally块


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

您是否确实在VM级别验证了这一点?大多数合理的编译器和GC在编译过程中将倾向于将两个块合并为一个块,并且在最后一次使用引用它的变量后,GC可以指定一个值。我没有验证垃圾收集,但我已经验证了范围。我很确定.NET垃圾收集器会收集那些已经离开作用域/未被引用的东西。GC可能会启动,但可能暂时不会!失去作用域并不意味着自动GC。此外,在本例中,对于值类型,GC将没有任何内容。这里的主要目的是确定范围,而不是GC。
switch( value )
{
    case const1: 
    {
        int i = GetValueSomeHow();
        //do something
        return i.ToString();
    }

    case const2:
    {
        int i = GetADifferentValue();
        //no exception now
        return SomeFunctionOfInt( i );
    }
 ...