Простенький вопрос к собеседованию
От: rg45 СССР  
Дата: 17.09.10 11:53
Оценка: 16 (1)
Тут вот в процессе работы родился простенький вопросик на понимание конструкции using.

Будет ли вызван метод Dispose в следующем фрагменте кода?
System.IO.FileStream file = null;
using (file)
{
    file = System.IO.File.OpenRead("some.bin");
}
--
Не можешь достичь желаемого — пожелай достигнутого.
Re: Простенький вопрос к собеседованию
От: Lloyd Россия  
Дата: 17.09.10 12:03
Оценка:
Здравствуйте, rg45, Вы писали:

R>Будет ли вызван метод Dispose в следующем фрагменте кода?

R>
R>System.IO.FileStream file = null;
R>using (file)
R>{
R>    file = System.IO.File.OpenRead("some.bin");
R>}
R>



Нет. Dispose-иться будет результат вычисления выражения в using-е, т.е. null.
Re: Простенький вопрос к собеседованию
От: LF  
Дата: 17.09.10 12:07
Оценка:
Это
R>
R>System.IO.FileStream file = null;
R>using (file)
R>{
R>    file = System.IO.File.OpenRead("some.bin");
R>}
R>

перепишется в такое вроде бы:
FileStream file = null;
FileStream file1 = file;
try{
  file = System.IO.File.OpenRead("some.bin");
}
finaly{
  ((IDisposable)file1).Dispose();
}

Так что Dispose вызовится не у той ссылки.
Re: Простенький вопрос к собеседованию
От: _FRED_ Черногория
Дата: 17.09.10 12:09
Оценка: 2 (2) +4 -1 :))) :)))
Здравствуйте, rg45, Вы писали:

R>Тут вот в процессе работы родился простенький вопросик на понимание конструкции using.


Сомневаюсь, что вопрос "на понимание". Скорее "на знание" (пробовал\не пробовал) или "на память" (читал\не читал).

Ну нафик. Лучше уж про виртуальный деструктор спросить.
Help will always be given at Hogwarts to those who ask for it.
Re[2]: Простенький вопрос к собеседованию
От: MozgC США http://nightcoder.livejournal.com
Дата: 17.09.10 12:25
Оценка: 1 (1) +2
Здравствуйте, _FRED_, Вы писали:

_FR>Сомневаюсь, что вопрос "на понимание". Скорее "на знание" (пробовал\не пробовал) или "на память" (читал\не читал).


Да про такое даже прочитать где-то сложно, так что в практической надобности такого вопроса я сомневаюсь. Лично я бы конечно заподозрил и ответил, что нет, но не был бы точно уверен почему.
Сейчас специально открыл Рихтера, Албахари и спецификацию C# и нигде не нашел описания такого случая. Так что если надо кого-то завалить на собеседовании и почувствовать своё превосходство, то да, вопрос хороший.
Re[2]: Простенький вопрос к собеседованию
От: _FRED_ Черногория
Дата: 17.09.10 12:29
Оценка: +1
Здравствуйте, _FRED_, Вы писали:

R>>Тут вот в процессе работы родился простенький вопросик на понимание конструкции using.


_FR>Сомневаюсь, что вопрос "на понимание". Скорее "на знание" (пробовал\не пробовал) или "на память" (читал\не читал).

_FR>Ну нафик. Лучше уж про виртуальный деструктор спросить.

В пользу безполезности вопроса высказывается и компилятор:

warning CS0728: Possibly incorrect assignment to local 'file' which is the argument to a using or lock statement. The Dispose call or unlocking will happen on the original value of the local.

А спрашивать о том, что произойдёт, когда компилятор это сам скажет, не должно.
Help will always be given at Hogwarts to those who ask for it.
Re[3]: Простенький вопрос к собеседованию
От: rg45 СССР  
Дата: 17.09.10 12:44
Оценка: -6
Здравствуйте, MozgC, Вы писали:

MC>Здравствуйте, _FRED_, Вы писали:


_FR>>Сомневаюсь, что вопрос "на понимание". Скорее "на знание" (пробовал\не пробовал) или "на память" (читал\не читал).


MC>Да про такое даже прочитать где-то сложно, так что в практической надобности такого вопроса я сомневаюсь. Лично я бы конечно заподозрил и ответил, что нет, но не был бы точно уверен почему.

MC>Сейчас специально открыл Рихтера, Албахари и спецификацию C# и нигде не нашел описания такого случая. Так что если надо кого-то завалить на собеседовании и почувствовать своё превосходство, то да, вопрос хороший.

Ну зря вы так в штыки. Если вдуматься, то это вполне логичное осмысленное поведение. И вот небольшой пример, иллюстрирующий полезность такого поведения:
    class InboundMessageBuffer : IDisposable
    {
        public int Read(byte[] data, int offset, int count)
        {
            return _stream.Read(data, offset, count);
        }

        public void PushInboundMessage(byte[] bytes)
        {
            // Вот так элегантно освобождается старый буфер и создается новый 
            using (_stream)
                _stream = new MemoryStream(bytes);
        }

        public void Dispose()
        {
            using (_stream)
            { }
        }
        #region Implementation
        MemoryStream _stream;
        #endregion
    };

И знать это нужно не для того чтоб кого-то завалить и показать свое превосходство, а в первую очередь для того, чтоб правильно и эффективно использовать предоставляемые платформой и языком возможности.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[3]: Простенький вопрос к собеседованию
От: rg45 СССР  
Дата: 17.09.10 12:55
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Здравствуйте, _FRED_, Вы писали:


R>>>Тут вот в процессе работы родился простенький вопросик на понимание конструкции using.


_FR>>Сомневаюсь, что вопрос "на понимание". Скорее "на знание" (пробовал\не пробовал) или "на память" (читал\не читал).

_FR>>Ну нафик. Лучше уж про виртуальный деструктор спросить.

_FR>В пользу безполезности вопроса высказывается и компилятор:

_FR>

_FR>warning CS0728: Possibly incorrect assignment to local 'file' which is the argument to a using or lock statement. The Dispose call or unlocking will happen on the original value of the local.

_FR>А спрашивать о том, что произойдёт, когда компилятор это сам скажет, не должно.

Да, это результат того, что пример был максимально упрощен. Если заменить локальную переменную на поле класса, то компилятор уже не выдает такого предупреждения (пример здесь
Автор: rg45
Дата: 17.09.10
). При этом идея-то сохраняется.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[4]: Простенький вопрос к собеседованию
От: sailichev  
Дата: 17.09.10 12:57
Оценка:
а чем это ваше
using (_stream)
_stream = new MemoryStream(bytes);

отличается от
using (_stream)
;
_stream = new MemoryStream(bytes);

или от
using (_stream) { }

_stream = new MemoryStream(bytes);

??


всмысле где связь между операторами?
Меня постоянно преследуют умные мысли. Но я быстрее.
Re[4]: Простенький вопрос к собеседованию
От: LF  
Дата: 17.09.10 13:00
Оценка: 1 (1)
Очень не очевидно, не понятно что экономим и ради чего.
Re[4]: Простенький вопрос к собеседованию
От: Аноним  
Дата: 17.09.10 13:01
Оценка:
Здравствуйте, rg45, Вы писали:

R>
R>    class InboundMessageBuffer : IDisposable
R>    {
R>        public int Read(byte[] data, int offset, int count)
R>        {
R>            return _stream.Read(data, offset, count);
R>        }

R>        public void PushInboundMessage(byte[] bytes)
R>        {
R>            // Вот так элегантно освобождается старый буфер и создается новый 
R>            using (_stream)
R>                _stream = new MemoryStream(bytes);
R>        }

R>        public void Dispose()
R>        {
R>            using (_stream)
R>            { }
R>        }
R>        #region Implementation
R>        MemoryStream _stream;
R>        #endregion
R>    };
R>


и чем выделенное элегантнее в этих местах, чем
stream.Dispose();

?

з.ы. в теле последнего метода так вообще using чужеродно выглядит
Re[4]: Простенький вопрос к собеседованию
От: Mr.Cat  
Дата: 17.09.10 13:05
Оценка:
Здравствуйте, rg45, Вы писали:
R>
R>            // Вот так элегантно освобождается старый буфер и создается новый 
R>            using (_stream)
R>                _stream = new MemoryStream(bytes);
R>        ...
R>            using (_stream)
R>            { }
R>

Ради чего все это?
Re[4]: Простенький вопрос к собеседованию
От: Аноним  
Дата: 17.09.10 13:06
Оценка: 1 (1) +4
Здравствуйте, rg45, Вы писали:

R>Да, это результат того, что пример был максимально упрощен. Если заменить локальную переменную на поле класса, то компилятор уже не выдает такого предупреждения (пример здесь
Автор: rg45
Дата: 17.09.10
). При этом идея-то сохраняется.


идея не ясна. потрудитесь донести ее более доходчиво. зачем сие, для чего такое знание, и где такое используется? приведенный пример не прошел бы code review в большинстве компаний
Re[4]: Простенький вопрос к собеседованию
От: MozgC США http://nightcoder.livejournal.com
Дата: 17.09.10 13:07
Оценка: +5
Здравствуйте, rg45, Вы писали:

R>Ну зря вы так в штыки. Если вдуматься, то это вполне логичное осмысленное поведение.


По моему скромному мнению, в этом коде:

System.IO.FileStream file = null;
using (file)
{
    file = System.IO.File.OpenRead("some.bin");
}

логичным и осмысленным лично для меня был бы вызов Dispose().

R>И вот небольшой пример, иллюстрирующий полезность такого поведения:

R>
R>    class InboundMessageBuffer : IDisposable
R>    {
R>        public int Read(byte[] data, int offset, int count)
R>        {
R>            return _stream.Read(data, offset, count);
R>        }

R>        public void PushInboundMessage(byte[] bytes)
R>        {
R>            // Вот так элегантно освобождается старый буфер и создается новый 
R>            using (_stream)
R>                _stream = new MemoryStream(bytes);
R>        }

R>        public void Dispose()
R>        {
R>            using (_stream)
R>            { }
R>        }
R>        #region Implementation
R>        MemoryStream _stream;
R>        #endregion
R>    };
R>

Интересно, одного меня пугает этот код?
Re[4]: Простенький вопрос к собеседованию
От: _FRED_ Черногория
Дата: 17.09.10 13:39
Оценка:
Здравствуйте, rg45, Вы писали:

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

R>            // Вот так элегантно освобождается старый буфер и создается новый 
R>            using (_stream)
R>                _stream = new MemoryStream(bytes);


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

R>И знать это нужно не для того чтоб кого-то завалить и показать свое превосходство, а в первую очередь для того, чтоб правильно и эффективно использовать предоставляемые платформой и языком возможности.


Вопрос не в том, "зачем это нужно знать", а в том, "зачем это спрашивать на собеседовании". Знать это, несомненно, полезно, но спрашивать: Ну разве что только в том случае, что вы уже положительно решили взять человека.
Help will always be given at Hogwarts to those who ask for it.
Re[4]: Простенький вопрос к собеседованию
От: rg45 СССР  
Дата: 17.09.10 13:43
Оценка:
Здравствуйте, rg45, Вы писали:

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

R>
...


Отвечать по отдельности каждому затруднительно, постараюсь ответить одним постом на все вопросы.

Соглашусь, пример не очень удачный и возникшие вопросы закономерны. Что скажете на счет такого: допустим, есть фасадный класс, инкапсулируюший в себе несколько объектов, реализующих интерфейс IDisposable. Сам фасадный класс также реализует интерфейс IDisposable и должен при своем разрушении освободить все агрегированные объекты. Поскольку агрегированные объекты так или иначе создаются последовательно, то существует вероятность возникновения исключения, когда часть объектов уже созданы, а часть еще нет. В этой ситуации необходимо обеспечить корректное освобождение всех ресурсов, захваченных на момент возникновения исключения. При этом хочется, чтоб код был по возможности компактным и читабельным. Я в этих случаях обычно поступаю так:
    class SomeFacade : IDisposable
    {
        public SomeFacade()
        {
            try
            {
                _disposable1 = CreateDisposable1();
                _disposable2 = CreateDisposable2();
                _disposable3 = CreateDisposable3();
            }
            catch
            {
                using (this)
                    throw;
            }
        }

        public void Dispose()
        {
            using (_disposable1)
            using (_disposable1)
            using (_disposable1)
            { }
        }

        private IDisposable _disposable1;
        private IDisposable _disposable2;
        private IDisposable _disposable3;
    }


Преимущество конструкции using вместо явного вызова Dispose становится более очевидным, когда разрушаемых объектов много. Сравните:
        public void Dispose()
        {
            if (_disposable1 != null)
                _disposable1.Dispose();

            if (_disposable2 != null)
                _disposable2.Dispose();

            if (_disposable3 != null)
                _disposable3.Dispose();
        }

Что же касается полезности того, что конструкция using лочит состояние ссылки на момент входа, и не отслеживает изменение переменной внутри блока, то, ИМХО, все становится достаточно очевидно, если вспомнить что аргументами конструкции using могут быть не только идентификаторы переменных, но и произвольные выражения. В этом плане запись: using (someDisposable) ничем не отличается от записи using (SomeDisposable.CreateInstance()). Т.е. в первом случае, так же как и во втором, идентификатор someDisposable играет роль выражения, значение которго и будет "защелкнуто" конструкцией using. И я не согласен с теми, кто утверждал, что это невозможно сообразить, а можно только прочесть или обнаружить эмпирически. И уж тем более не согласен с теми, кто утверждает, что знать это не обязательно.

Я на все вопросы ответил?
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[5]: Простенький вопрос к собеседованию
От: Аноним  
Дата: 17.09.10 13:49
Оценка:
Здравствуйте, rg45, Вы писали:

R>Соглашусь, пример не очень удачный и возникшие вопросы закономерны. Что скажете на счет такого: допустим, есть фасадный класс, инкапсулируюший в себе несколько объектов, реализующих интерфейс IDisposable. Сам фасадный класс также реализует интерфейс IDisposable и должен при своем разрушении освободить все агрегированные объекты...


но конструктор не отработал, значит экземпляр класса не создан. должен ли он заниматся саморазрушением? имхо вопрос тут в архитектуре...
Re[6]: Простенький вопрос к собеседованию
От: rg45 СССР  
Дата: 17.09.10 13:57
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, rg45, Вы писали:


R>>Соглашусь, пример не очень удачный и возникшие вопросы закономерны. Что скажете на счет такого: допустим, есть фасадный класс, инкапсулируюший в себе несколько объектов, реализующих интерфейс IDisposable. Сам фасадный класс также реализует интерфейс IDisposable и должен при своем разрушении освободить все агрегированные объекты...


А>но конструктор не отработал, значит экземпляр класса не создан. должен ли он заниматся саморазрушением? имхо вопрос тут в архитектуре...


Он успел создать некоторые объекты, реализующие интерфейс IDisposable. И если он их не разрушит то это чревато утечками системных ресурсов — неуправляемой памяти, объектами ядра, подвисшими потоками и даже процессами. Ведь понятие системных ресурсов несколько шире, выделение и освобождение памяти и освобождение далеко не всех ресурсов по зубам сборщику мусора.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[5]: Простенький вопрос к собеседованию
От: LF  
Дата: 17.09.10 13:58
Оценка:
Я бы решил задачу так:
class Util{
  public static void CheckAndDispose(IDisposable obj){
    if (obj != null)
      obj.Dispose();
  }
}

...
  public Dispose(){
    Util.CheckAndDispose(_disposable1);
    Util.CheckAndDispose(_disposable2);
    Util.CheckAndDispose(_disposable3);
  }

Сразу понятно что, кто и зачем.
А использование using для этих целей похоже на хак с недокументированными возможностями.
Не для того using придуман был.
Re[2]: Простенький вопрос к собеседованию
От: Jesmus Россия  
Дата: 17.09.10 14:14
Оценка: +1
Здравствуйте, _FRED_, Вы писали:

_FR>Сомневаюсь, что вопрос "на понимание". Скорее "на знание" (пробовал\не пробовал) или "на память" (читал\не читал).


Вот тут не соглашусь. Как-то проблем с ответом не возникло ни у меня, ни у коллег — хотя и не пробовал никто такого. Наверное каждый кто пытался представить во что будет разворачиваться using конструкция ответит без проблем.

Однако зачем такое спрашивать на собеседовании не пойму. Что покажет ответ на этот вопрос? Тогда уже лучше сразу попросить написать эквивалент using — по крайней мере покажет что человек не угадывал, а понимает как оно работает.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.