Есть ли гарантия порядка, в котором вызывается метод Dispose () при использовании нескольких операторов using для одной и той же области видимости в C #? - PullRequest
3 голосов
/ 28 октября 2011
using (Stuff1 stf1 = new Stuff1(...)) // Allocation of stf1
using (Stuff2 stf2 = new Stuff2(...)) // Allocation of stf2
{
    try
    {
        // ... do stuff with stf1 and stf2 here ...
    }
    catch (Stuff1Exception ex1)
    {
        // ...
    }
    catch (Stuff2Exception ex2)
    {
        // ...
    }
} // Automatic deterministic destruction through Dispose() for stf1/stf2 - but in which order?

Другими словами, гарантированно ли сначала вызывается метод disf () stf2, а затем гарантированно вызывается второй метод stf1 Dispose ()? (в основном: методы Dispose (), вызываемые в обратном порядке выделения объекта, которому они принадлежат?)

Ответы [ 6 ]

6 голосов
/ 28 октября 2011

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

if (...)
    if (...)
    {

    }

Было бы понятно, какой порядок действий имеет место (не то, чтобы я рекомендовал эту конкретную структуру), потому что он точно такой же, как этот:1005 *

Так же и с using.Ваш код ничем не отличается от следующего:

using (...)
{
    using(...)
    {

    }
}

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

2 голосов
/ 28 октября 2011

Оператор использования в любом случае преобразуется в try-finally. Это просто синтаксический сахар ... так что вы правы в том, что ваш пример будет переведен как следующий во время компиляции:

try
{
    Stuff1 stf1 = new Stuff1());
    try
    {
        Stuff2 stf2 = new Stuff2();
    }
    finally
    {
        stf2.Dispose();
    }
}
finally
{
    stf1.Dispose();
}
2 голосов
/ 28 октября 2011

Да, сначала вызывается stf2.Dispose, а затем - stf1. Dispose

1 голос
/ 28 октября 2011

Stuff2 будет утилизирован перед Stuff1, потому что он находится во внутреннем блоке.

Даже если вы не использовали фигурные скобки на внешнем блоке для Stuff1, это все равно, как если бы вы использовали.

1 голос
/ 28 октября 2011

Нет гарантии из-за возможного повторного заказа.Dispose вызывается на закрывающей фигурной (или неявной в вашем примере).Вы всегда увидите ожидаемый порядок в неоптимизированных сборках Debug.Вы можете использовать Thread.MemoryBarrier для принудительного определения порядка операций.

using (Stuff1 stf1 = new Stuff1(...)) // Allocation of stf1
using (Stuff2 stf2 = new Stuff2(...)) // Allocation of stf2
{ {
    try
    {
        // ... do stuff with stf1 and stf2 here ...
    }
    catch (Stuff1Exception ex1)
    {
        // ...
    }
    catch (Stuff2Exception ex2)
    {
        // ...
    }
} Thread.MemoryBarrier(); }

Оптимизация режима выпуска выполняется таким образом, чтобы гарантировать предсказуемые результаты в этом потоке после выполнения всех инструкций,Все остальное (вид из другого потока на отдельном ядре) готово к работе.Это не противоречит правилам, когда возникает ситуация, когда stf2 еще не расположен, а stf1 расположен, как это видно из другого потока.Если вы не форсируете порядок операций.Попробуйте написать несколько утверждений и запустить под Jinx

0 голосов
/ 28 октября 2011

Да, метод Dispose будет вызываться в конце области применения, поэтому методы Dispose () вызываются в обратном порядке выделения объекта, которому они принадлежат

...