Страницы

Поиск по вопросам

суббота, 7 декабря 2019 г.

Неочевидное поведение блока using в C#

#c_sharp #net #dispose


Наткнулся на такой необычный код на METANIT. Объявлена структура:

public struct S : IDisposable
{
    private bool dispose;
    public void Dispose()
    {
        dispose = true;
    }
    public bool GetDispose()
    {
        return dispose;
    }
}


И есть такой код, который использует ее:

var s = new S();
using (s)
{
    Console.WriteLine(s.GetDispose());
}
Console.WriteLine(s.GetDispose());


Код выводит false, false, хотя казалось, что должно выводиться false, true. Самое
интересное то, что если структуру S сделать классом, то будет выводиться ожидаемое
значение :)

Объясните, что происходит за кулисами с переменной s? Почему для структуры будет
false, false, а для класса - false, true
    


Ответы

Ответ 1



Ваш код с using разворачивается следующим образом: var s = new S(); var using_s = s; try { Console.WriteLine(s.GetDispose()); } finally { using_s.Dispose(); } Console.WriteLine(s.GetDispose()); using вызыват Dispose не на вашей переменной s а на своей собственной переменной. И соответственно поле dispose обновляется не у переменной s. Для примера можно рассмотреть следующий код: using System; public static class Program { public static void Main() { var s = new S(); using (s) { s.Mark = 42; Console.WriteLine(s.GetDispose()); } Console.WriteLine(s.GetDispose()); var c1 = new C(); using (c1) { c1.Mark = 42; Console.WriteLine(c1.GetDispose()); } Console.WriteLine(c1.GetDispose()); var c2 = new C(); using (c2) { c2 = new C { Mark = 42 }; Console.WriteLine(c2.GetDispose()); } Console.WriteLine(c2.GetDispose()); } } public struct S : IDisposable { public int Mark; private bool dispose; public void Dispose() { Console.WriteLine(Mark); dispose = true; } public bool GetDispose() { return dispose; } } public class C : IDisposable { public int Mark; private bool dispose; public void Dispose() { Console.WriteLine(Mark); dispose = true; } public bool GetDispose() { return dispose; } } В случаях s.Mark = 42; и c2 = new C { Mark = 42 }; назначение переменной внутри блока using не влияет на значение поля Mark, выводимое методом Dispose, так как using вызывает Dispose на своей собственной переменной. И компилятор даже выводит соответствующие предупреждение. В случае с c1.Mark = 42; происходит не изменение переменной, а изменение объекта, на который она указывает.

Комментариев нет:

Отправить комментарий