Какова ценность анонимного непривязанного блока в С#?

В С# вы можете сделать блок внутри метода, который не привязан к какому-либо другому утверждению.

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

            {
                int z = 42;
                int zz = z;
            }
        }
    }

Этот код компилируется и выполняется так же, как если бы скобки внутри основного метода не были. Также обратите внимание на блок внутри блока.

Есть ли сценарий, где это было бы ценно? Я еще не нашел, но мне интересно узнать о других людях.

Ответ 1

Объем и сбор мусора. Когда вы покидаете непривязанный блок, любые объявленные в нем переменные выходят за рамки. Это позволяет сборщику мусора очистить эти объекты.

Ray Hayes указывает, что сборщик мусора .NET не будет немедленно собирать объекты вне области видимости, поэтому основным преимуществом является область охвата.

Ответ 2

Примером может быть, если вы хотите повторно использовать имя переменной, обычно вы не можете повторно использовать имена переменных Это недопустимо

        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

Ответ 3

Это побочный продукт правила синтаксического анализатора, который является либо простым оператором, либо блоком. то есть блок может использоваться везде, где может быть один оператор.

например.

if (someCondition)
 SimpleStatement();

if (SomeCondition)
{
   BlockOfStatements();
}

Другие указали, что объявления переменных находятся в области действия до конца содержащего блока. Хорошо, что временные vars имеют небольшой объем, но мне никогда не приходилось использовать блок, чтобы ограничить область действия переменной. Иногда вы используете блок под инструкцией "using" для этого.

Так что вообще это не ценно.

Ответ 4

Насколько я вижу, это было бы полезно только с организационной точки зрения. Я не могу представить себе какую-либо логическую ценность при этом. Возможно, у кого-то будет подходящий пример.

Ответ 5

Это позволяет вам создать блок видимости в любом месте. Это не то, что полезно на нем, но может сделать логику проще:

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
 ...

В С# мы можем использовать блок scope, чтобы элементы, объявленные в каждом случае, были только в области в этом случае:

switch( value )
{
    case const1: 
    {
        int i = GetValueSomeHow();
        //do something
        return i.ToString();
    }

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

Это также может работать для gotos и меток, а не для того, чтобы вы часто использовали их на С#.

Ответ 6

Единственная практическая причина, по которой она существует, заключается в том, что вы хотите ограничить область действия некоторой переменной, если нет необходимости вводить какую-либо другую причину для блока. На практике это практически никогда не бывает полезным.

Лично я полагаю, что с точки зрения языка/компилятора проще сказать, что вы можете поместить блок в любом месте, где ожидается утверждение, и они просто не уходили с пути, чтобы не позволить вам использовать его без объявления if/for/method/etc.

Рассмотрим начало этого последнего сообщения в блоге от Эрика Липперта. За оператором if не следует ни один оператор, либо несколько операторов, заключенных в фигурные скобки, а просто один оператор. Каждый раз, когда вы вставляете от 0 до N операторов в фигурные скобки, вы делаете этот раздел эквивалентного кода (с точки зрения анализатора языка) одним утверждением. Эта же практика применяется и ко всем структурам цикла, хотя, как объясняет главный пункт сообщения в блоге, это не относится к блокам try/catch/finally.

При обращении к блокам с этой точки зрения возникает вопрос: "Есть ли веская причина предотвратить использование блоков в любом месте, где можно использовать один оператор?" и ответ: "Нет".

Ответ 7

Одна из причин этого заключается в том, что переменные "z" и "zz" не будут доступны для кода ниже конца этого внутреннего блока. Когда вы делаете это в Java, JVM подталкивает стек стека для внутреннего кода, и эти значения могут находиться в стеке. Когда код выходит из блока, стек стека открывается, и эти значения исчезают. В зависимости от типов, это может избавить вас от необходимости использовать кучу и/или сборку мусора.

Ответ 8

В С# - как c/С++/java - фигурные скобки обозначают область. Это определяет время жизни переменной. По достижении конечной скобки переменная становится сразу доступной для сбора мусора. В С++ это вызовет вызов деструктора класса, если var представляет экземпляр.

Как для использования, единственное возможное использование - освободить большой объект, но tbh, установив его в null, будет иметь тот же эффект. Я подозреваю, что прежнее использование, вероятно, просто для того, чтобы программисты на C++ переходили к управляемому коду на знакомой и удобной территории. Если вы действительно хотите вызвать "деструктор" в С#, вы обычно реализуете интерфейс IDisposable и используете шаблон "using (var) {...}".

Ойсин

Ответ 9

Даже если это было действительно полезно по какой-либо причине (например, управление видимостью переменной), я бы отговорил вас от такой конструкции с точки зрения хорошей старой читаемости кода.

Ответ 10

Для этого не существует значения, кроме семантики, а также для области видимости и сбора мусора, ни одна из которых не является существенной в этом ограниченном примере. Если вы считаете, что он делает код более понятным, для себя и/или других, то вы, конечно, можете его использовать. Тем не менее, более приемлемое соглашение для смыслового разъяснения в коде обычно использует разрывы строк только с опциональными комментариями в строке:

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