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[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[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[7]: Простенький вопрос к собеседованию
От: Аноним  
Дата: 17.09.10 16:25
Оценка: 10 (2) +1
Здравствуйте, rg45, Вы писали:

R>Зло и неконструктивно.


хотите конструктивно? ок. using добавлен в язык для детерминированного уничтожения объектов. его использование подразумевает некий scope за пределами которого происходит разрушение объекта. ни один из ваших примеров НЕ вписывается в предназначение using. то, что вы делаете — это действительно сродни хаку. разработчик не ждет такого его использования.
Re[2]: Простенький вопрос к собеседованию
От: MozgC США http://nightcoder.livejournal.com
Дата: 17.09.10 12:25
Оценка: 1 (1) +2
Здравствуйте, _FRED_, Вы писали:

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


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

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


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


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


Дело в том, что когда задаётся такой вот вопрос, то, если не знаешь точный ответ, варианта поиска решения два:
Как оно окажется по-правде — соображалки определить не удастся. То есть получаются угадалочки.
Help will always be given at Hogwarts to those who ask for it.
Re[9]: Простенький вопрос к собеседованию
От: Аноним  
Дата: 18.09.10 08:32
Оценка: 28 (2)
Здравствуйте, rg45, Вы писали:

R>Хорошо, допустим, убедили. Как предлагаете решать проблему, с исключениями, описанную мной здесь: Dispose и исключения
Автор: rg45
Дата: 18.09.10
?

я считаю, что если один из Dispose кидает исключение, то это как бы совсем плохо и нада падать. не должен Dispose кидать исключения и все тут. ну на мой взгляд это таки да — сродни исключениям в деструкторе С++.
в любом случае в случае исключения в одном из Dispose, а потом в одном из следующих (в вашем примере) произойдет утеря исходного исключения (я о исключении в первом Dispose). вот еще реальный пример:
            sealed class Disposable : IDisposable
            {
                public void Dispose()
                {
                    throw new NotImplementedException();
                }
            }
            ...
            try
            {
                using (var disposable = new Disposable())
                {
                    throw new OutOfMemoryException();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }

Результат: System.NotImplementedException: The method or operation is not implemented.


что будет если в Disaposable.Dispose кинет исключение? будет утеряно рабочее исключение. совсем не гуд. ошибка как бы есть, но стерта новой (возможно абсолютно неинтересной юзеру типа ArgumentNullException. а что с ним делать? логировать и падать).

R>Кстати, почему анонимно?

так быстрее )
Re[8]: Простенький вопрос к собеседованию
От: Lloyd Россия  
Дата: 17.09.10 16:21
Оценка: 1 (1) +1
Здравствуйте, rg45, Вы писали:

L>>Только то, что вы за замысловатыми конструкциями прячете простой по сути код. Зачем делать сложно, когда можно сделать просто?


R>Правильно ли я понял мысль, "простой по сути код" должен выглядеть так:

R>
R>            catch
R>            {
R>                Dispose();
R>                throw;
R>            }
R>        }

R>        public void Dispose()
R>        {
R>            Util.CheckAndDispose(_disposable1);
R>    }
R>

R>???

Да я бы и Util.CheckAndDispose убрал бы. Экономии — ноль.

R>И какие конструкции в моем коде кажутся замысловатыми, эти что ли:

R>
R>using (disposable1) { }
R>

R>???

Да. Если у вас есть возражение, предлагаю почитать, для чего был придуман using и убедиться, что не для этого.

R>Потрясающе!!! Неужели действительно непонятно какой эффект произведет эта конструкция? А вот у меня гораздо большее недоверие вызовет конструкция:

R>
R>Util.CheckAndDispose(_disposable1);
R>

R>Потому что это еще надо проверять, нет ли в ней ошибок, утечек и т.д.

Зачем?

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


Если вы код пишете исключаительно для себя, то без проблем. Если же вы работаете в команде, то стоит прислушиваться к мнению окружающих.
Re[6]: Простенький вопрос к собеседованию
От: Pro100Oleh Украина  
Дата: 18.09.10 07:02
Оценка: 1 (1) +1
Здравствуйте, Аноним, Вы писали:

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


Раз было выполнение конструктора, то экземпляр был создан. Когда-то здесь на форуме уже обсуждалась разница восприятия конструктора в дотнете и в си.

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

Саморазрушение — неудачное слово. Это больше относится к деструктору. Здесь идет речь о освобождении захваченных ресурсов, а их освободить может только класс-хозяин. А Dispose метод должен всегда учитывать случай, что инстанс может быть в неопределенном состоянии.

ЗЫ: Вот только дизайн класса выше мне совсем не нравится.
Pro
Re[7]: Простенький вопрос к собеседованию
От: Pro100Oleh Украина  
Дата: 18.09.10 08:14
Оценка: 1 (1) +1
Здравствуйте, hardcase, Вы писали:

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


PO>>Вот решение для случая, когда ресурсы класса создаются в конструкторе:


H>Финализатор в данном конкретном случае совсем не обязателен, так как из ресурсов у нас только единственный управляемый объект Stream.


Stream рассматривайте только как пример (видимо неудачный).
Pro
Re[8]: Простенький вопрос к собеседованию
От: rg45 СССР  
Дата: 17.09.10 14:31
Оценка: -2
Здравствуйте, sailichev, Вы писали:

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


S>Сравнил.

S>This is bad because it is misleading. (с)

Вот так вот! Аргументы кончились, поэтому претендуем на абсолютную истину
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[9]: Простенький вопрос к собеседованию
От: sailichev  
Дата: 17.09.10 14:58
Оценка: +2
Здравствуйте, rg45, Вы писали:

R>Вот так вот! Аргументы кончились, поэтому претендуем на абсолютную истину


я не верю что вам самому нравится ваш не_очевидный код после всего здесь услышанного.
советую применить то что предложено выше. сообщать о данном действии не обязательно =)
Меня постоянно преследуют умные мысли. Но я быстрее.
Re[5]: Простенький вопрос к собеседованию
От: Aviator  
Дата: 17.09.10 15:41
Оценка: +1 :)
Здравствуйте, rg45, Вы писали:
R>Я на все вопросы ответил?
Пытаемся судорожно изобрести новый паттерн ? Вам надо на с++ форум, там любят обсудить как бы так извратится что бы никто кроме автора кода не понял что написано. Да и сам автор через полгода уже не факт что вспомнит зачем он написал эту фигню .
Re[6]: Простенький вопрос к собеседованию
От: Lloyd Россия  
Дата: 17.09.10 15:45
Оценка: +2
Здравствуйте, rg45, Вы писали:

R>Все таки, хочется дойти в этом вопросе до какого-то логического завершения. Поймите меня правильно, я вовсе не горю желанием тупо спорить. Для меня очень важно сформировать правильную точку зрения по этому вопросу. Конечно, не только по этому, но по этому тоже. Возможно, я в чем-то заблуждаюсь, тогда я буду благодарен, если вы объясните мне мою ошибку. Давайте конструктивно, что по вашему мнению есть плохого или не правильного в этом примере? Только просьба, давайте временно (подчеркиваю — временно) вопрос привычности и понятности кода оставим за скобками, и рассмотрим сугубо техническую часть проблемы.


Только то, что вы за замысловатыми конструкциями прячете простой по сути код. Зачем делать сложно, когда можно сделать просто?
Простенький вопрос к собеседованию
От: 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[12]: Простенький вопрос к собеседованию
От: Pro100Oleh Украина  
Дата: 18.09.10 13:20
Оценка: 6 (1)
Здравствуйте, Аноним, Вы писали:

А> только все равно не ясно как быть с потерянными исключениями


[вне контекста о Dispose]
Когда надо гарантирванно вызвать несколько методов, где каждый может упасть, используют коллекцию экзепшинов. Как пример — System.ComponentModel.Design<br />
.ExceptionCollection
Pro
Re[4]: Простенький вопрос к собеседованию
От: LF  
Дата: 17.09.10 13:00
Оценка: 1 (1)
Очень не очевидно, не понятно что экономим и ради чего.
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[2]: Простенький вопрос к собеседованию
От: Jesmus Россия  
Дата: 17.09.10 14:14
Оценка: +1
Здравствуйте, _FRED_, Вы писали:

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


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

Однако зачем такое спрашивать на собеседовании не пойму. Что покажет ответ на этот вопрос? Тогда уже лучше сразу попросить написать эквивалент using — по крайней мере покажет что человек не угадывал, а понимает как оно работает.
Re[8]: Простенький вопрос к собеседованию
От: rg45 СССР  
Дата: 17.09.10 19:17
Оценка: +1
Здравствуйте, Аноним, Вы писали:

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


R>>Зло и неконструктивно.


А>хотите конструктивно? ок. using добавлен в язык для детерминированного уничтожения объектов. его использование подразумевает некий scope за пределами которого происходит разрушение объекта. ни один из ваших примеров НЕ вписывается в предназначение using. то, что вы делаете — это действительно сродни хаку. разработчик не ждет такого его использования.


Конструктивно, лаконично и явно не без здравого смысла. Спасибо. Беру тайм-аут на обмозговывание.
--
Не можешь достичь желаемого — пожелай достигнутого.
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[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]: Простенький вопрос к собеседованию
От: Аноним  
Дата: 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]: Простенький вопрос к собеседованию
От: _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[6]: Простенький вопрос к собеседованию
От: rg45 СССР  
Дата: 17.09.10 14:22
Оценка:
Здравствуйте, LF, Вы писали:

LF>Я бы решил задачу так:

LF>
LF>class Util{
LF>  public static void CheckAndDispose(IDisposable obj){
LF>    if (obj != null)
LF>      obj.Dispose();
LF>  }
LF>}

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

LF>Сразу понятно что, кто и зачем.
LF>А использование using для этих целей похоже на хак с недокументированными возможностями.
LF>Не для того using придуман был.

Не согласен. О каких недокументированных возможностях речь? О том, что оператор using может быть использован с нулевым аргументом? В MSDN это недвусмысленно зафиксировано: http://msdn.microsoft.com/en-us/library/yh598w02.aspx. Внимание на секцию Remarks и пример.

А что касается 'CheckAndDispose' — можно, конечно. Но зачем повсеместно делать то, чего можно не делать? Лишние сущности, лишний код, лишние нагромождения, дополнительная возможность допускать ошибки...
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[5]: Простенький вопрос к собеседованию
От: sailichev  
Дата: 17.09.10 14:23
Оценка:
Здравствуйте, rg45, Вы писали:

R>Преимущество конструкции using вместо явного вызова Dispose становится более очевидным, когда разрушаемых объектов много. Сравните:

R>
R>        public void Dispose()
R>        {
R>            if (_disposable1 != null)
R>                _disposable1.Dispose();

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

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



Ну тогда и вы сравните:

...
    public static class DisposableExtension
    {
        public static void MyDispose(this IDisposable d)
        {
            if (d != null)
                d.Dispose();
        }
    }
...
        public void Dispose()
        {
            _disposable1.MyDispose();
            _disposable1.MyDispose();
            _disposable1.MyDispose();
        }
...
Меня постоянно преследуют умные мысли. Но я быстрее.
Re[6]: Простенький вопрос к собеседованию
От: rg45 СССР  
Дата: 17.09.10 14:28
Оценка:
Здравствуйте, sailichev, Вы писали:

S>Ну тогда и вы сравните:

S>
...


Вы наверное не внимательно читали мой пост, сравнивать нужно как раз не с этим. Давайте ка еще разок сравним:
public void Dispose()
{
    using (_disposable1)
    using (_disposable1)
    using (_disposable1)
    { }
}

и
...
    public static class DisposableExtension
    {
        public static void MyDispose(this IDisposable d)
        {
            if (d != null)
                d.Dispose();
        }
    }
...
        public void Dispose()
        {
            _disposable1.MyDispose();
            _disposable1.MyDispose();
            _disposable1.MyDispose();
        }
...
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[7]: Простенький вопрос к собеседованию
От: sailichev  
Дата: 17.09.10 14:30
Оценка:
Здравствуйте, rg45, Вы писали:

Сравнил.
This is bad because it is misleading. (с)
Меня постоянно преследуют умные мысли. Но я быстрее.
Re[5]: Простенький вопрос к собеседованию
От: rg45 СССР  
Дата: 17.09.10 15:06
Оценка:
Здравствуйте, rg45, Вы писали:

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

R>
R>    class SomeFacade : IDisposable
R>    {
R>        public SomeFacade()
R>        {
R>            try
R>            {
R>                _disposable1 = CreateDisposable1();
R>                _disposable2 = CreateDisposable2();
R>                _disposable3 = CreateDisposable3();
R>            }
R>            catch
R>            {
R>                using (this)
R>                    throw;
R>            }
R>        }

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

R>        private IDisposable _disposable1;
R>        private IDisposable _disposable2;
R>        private IDisposable _disposable3;
R>    }
R>


Все таки, хочется дойти в этом вопросе до какого-то логического завершения. Поймите меня правильно, я вовсе не горю желанием тупо спорить. Для меня очень важно сформировать правильную точку зрения по этому вопросу. Конечно, не только по этому, но по этому тоже. Возможно, я в чем-то заблуждаюсь, тогда я буду благодарен, если вы объясните мне мою ошибку. Давайте конструктивно, что по вашему мнению есть плохого или не правильного в этом примере? Только просьба, давайте временно (подчеркиваю — временно) вопрос привычности и понятности кода оставим за скобками, и рассмотрим сугубо техническую часть проблемы.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[6]: Простенький вопрос к собеседованию
От: rg45 СССР  
Дата: 17.09.10 15:46
Оценка:
Здравствуйте, Aviator, Вы писали:

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

R>>Я на все вопросы ответил?
A>Пытаемся судорожно изобрести новый паттерн ? Вам надо на с++ форум, там любят обсудить как бы так извратится что бы никто кроме автора кода не понял что написано. Да и сам автор через полгода уже не факт что вспомнит зачем он написал эту фигню .

Зло и неконструктивно.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[4]: Простенький вопрос к собеседованию
От: Uzzy Россия  
Дата: 17.09.10 16:01
Оценка:
Здравствуйте, _FRED_, Вы писали:

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


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


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


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


_FR>Дело в том, что когда задаётся такой вот вопрос, то, если не знаешь точный ответ, варианта поиска решения два:

_FR> _FR>Как оно окажется по-правде — соображалки определить не удастся. То есть получаются угадалочки.

Почему же не знаешь? В спецификации пункт 8.13 достаточно популярно расписывает, как раскладывается using statement. Так что тут никаких гаданий.
Re[7]: Простенький вопрос к собеседованию
От: rg45 СССР  
Дата: 17.09.10 16:11
Оценка:
Здравствуйте, Lloyd, Вы писали:

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


R>>Все таки, хочется дойти в этом вопросе до какого-то логического завершения. Поймите меня правильно, я вовсе не горю желанием тупо спорить. Для меня очень важно сформировать правильную точку зрения по этому вопросу. Конечно, не только по этому, но по этому тоже. Возможно, я в чем-то заблуждаюсь, тогда я буду благодарен, если вы объясните мне мою ошибку. Давайте конструктивно, что по вашему мнению есть плохого или не правильного в этом примере? Только просьба, давайте временно (подчеркиваю — временно) вопрос привычности и понятности кода оставим за скобками, и рассмотрим сугубо техническую часть проблемы.


L>Только то, что вы за замысловатыми конструкциями прячете простой по сути код. Зачем делать сложно, когда можно сделать просто?


Правильно ли я понял мысль, "простой по сути код" должен выглядеть так:
    public class Util
    {
        public static void CheckAndDispose(IDisposable obj)
        {
            if (obj != null)
                obj.Dispose();
        }
    }

    class SomeFacade : IDisposable
    {
        public SomeFacade()
        {
            try
            {
                _disposable1 = CreateDisposable1();
                _disposable2 = CreateDisposable2();
                _disposable3 = CreateDisposable3();
            }
            catch
            {
                Dispose();
                throw;
            }
        }

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

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

???

И какие конструкции в моем коде кажутся замысловатыми, эти что ли:
using (disposable1) { }

???


Потрясающе!!! Неужели действительно непонятно какой эффект произведет эта конструкция? А вот у меня гораздо большее недоверие вызовет конструкция:
Util.CheckAndDispose(_disposable1);

Потому что это еще надо проверять, нет ли в ней ошибок, утечек и т.д.

Извините, не убедили, мой код мне кажется более простым, более надежным и более читабельным.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[4]: Простенький вопрос к собеседованию
От: Uzzy Россия  
Дата: 17.09.10 16:40
Оценка:
Здравствуйте, rg45, Вы писали:

Напрягают два момента
1:
R>
R>        public void PushInboundMessage(byte[] bytes)
R>        {
R>            // Переписали так:
R>            using (_stream = GetResurce())
R>                _stream = new MemoryStream(bytes);
R>        }
R>


2:
Очень уж глаза режет то, что значение переопределяется после resource-acquisition внутри statement.
... << RSDN@Home 1.2.0 alpha 4 rev. 1270>>
Re[5]: Простенький вопрос к собеседованию
От: _FRED_ Черногория
Дата: 17.09.10 17:35
Оценка:
Здравствуйте, Uzzy, Вы писали:

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


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


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


_FR>>Дело в том, что когда задаётся такой вот вопрос, то, если не знаешь точный ответ, варианта поиска решения два:

_FR>> _FR>>Как оно окажется по-правде — соображалки определить не удастся. То есть получаются угадалочки.

U>Почему же не знаешь? В спецификации пункт 8.13 достаточно популярно расписывает, как раскладывается using statement. Так что тут никаких гаданий.


Так почему бы тогда просто не спросить (если именно это и интересует) собеседуемого: "спеку много думали?"

В том-то и паранойя данного вопроса: что он на "понимание" (слово топикстартера), в то время, как умение понимать никак на вопрос ответить не поможет: сгодится лишь "знание" ("пробовал") или "память" ("читал" [спецификацию, имеется в виду, если кто не понял]).
Help will always be given at Hogwarts to those who ask for it.
Re[5]: Простенький вопрос к собеседованию
От: hardcase Пират http://nemerle.org
Дата: 17.09.10 17:41
Оценка:
Здравствуйте, Uzzy, Вы писали:

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


U>Напрягают два момента

U>1:
R>>
R>>        public void PushInboundMessage(byte[] bytes)
R>>        {
R>>            // Переписали так:
R>>            using (_stream = GetResurce())
R>>                _stream = new MemoryStream(bytes);
R>>        }
R>>


U>2:

U>Очень уж глаза режет то, что значение переопределяется после resource-acquisition внутри statement.

Еще режет глаза тот факт, что _stream — это поле и при том мутабельное, хотя в данном примере это совсем не желательно.
/* иЗвиНите зА неРовнЫй поЧерК */
Re[6]: Простенький вопрос к собеседованию
От: rg45 СССР  
Дата: 17.09.10 19:01
Оценка:
Здравствуйте, _FRED_, Вы писали:

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


_FR>В том-то и паранойя данного вопроса: что он на "понимание" (слово топикстартера), в то время, как умение понимать никак на вопрос ответить не поможет: сгодится лишь "знание" ("пробовал") или "память" ("читал" [спецификацию, имеется в виду, если кто не понял]).


Есть один момент, который мне кажется странным в твоих рассуждениях. Почему ты отождествляешь категории "понимать" и "додуматься самому"? Это ведь не одно и тоже. Понимание чего-либо может быть результатом: а) логических рассуждений (додумался сам), б) анализа практического опыта и в) результатом вдумчивого изучения. Большинство из нас прекрасно понимают смысл интеграла и производной, но это совсем не означает, что все мы сами до этого додумались. Можно конечно же знать что либо, но при этом не понимать (как теорию относительности, например, или принцип наименьшего действия). Но я счел (это мое ИМХО), что в данном вопросе знание без понимания не имеет особой ценности, поэтому и написал — что вопрос на понимание. Знание также подразумевается, потому что понимать, не зная, вряд ли возможно.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[6]: Dispose и исключения
От: rg45 СССР  
Дата: 18.09.10 00:51
Оценка:
Здравствуйте, LF, Вы писали:

Давайте еще раз сравним два варианта:

такой:
  public Dispose(){
    using(_disposable1)
    using(_disposable2)
    using(_disposable3)
    { } 
  }

и такой:
  public Dispose(){
    Util.CheckAndDispose(_disposable1);
    Util.CheckAndDispose(_disposable2);
    Util.CheckAndDispose(_disposable3);
  }

А теперь допустим, что во время вызова _disposable1.Dispose() возникает исключение. В первом случае, не смотря на это исключение, метод Dispose для объектов _disposable2 и _disposable3 будет вызван. А во втором не будет. И если в верхних слоях программы это исключение перехватывается, то весь этот сценарий может повториться снова и снова. Со всеми вытекающими последствиями. Как быть? Поместим CheckAndDispose во вложенные блоки try-catch? И во что после этого превратится Ваше "просто и понятно"?

Конечно же вопрос о том должны ли из методов Dispose лететь исключения или не должны — вопрос сам по себе не тривиальный. Напрмер, в C++ есть заповедь (если можно так выразиться), что деструкторы не должны бросать исключений. Но, во-первых, исключения могут лететь из вызываемых внутри деструкторов функций, и вряд ли будет хорошо, если деструктор будет тупо давить все подряд исключения. А во-вторых, Dispose существенно отличается от деструкторов C++ и многие из обоснований, справедливых для деструкторов не применимы для Dispose.

Ну и наконец, хорошо ли плохо ли, но факт остается фактом: исключения могут лететь из Dispose и сбрасывать со счетов этот факт нельзя.

Что скажете? (Вопрос не только к LF).
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[8]: Простенький вопрос к собеседованию
От: rg45 СССР  
Дата: 18.09.10 06:52
Оценка:
Здравствуйте, Аноним, Вы писали:

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


R>>Зло и неконструктивно.


А>хотите конструктивно? ок. using добавлен в язык для детерминированного уничтожения объектов. его использование подразумевает некий scope за пределами которого происходит разрушение объекта. ни один из ваших примеров НЕ вписывается в предназначение using. то, что вы делаете — это действительно сродни хаку. разработчик не ждет такого его использования.


Хорошо, допустим, убедили. Как предлагаете решать проблему, с исключениями, описанную мной здесь: Dispose и исключения
Автор: rg45
Дата: 18.09.10
?

Кстати, почему анонимно?
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[4]: Простенький вопрос к собеседованию
От: Pro100Oleh Украина  
Дата: 18.09.10 07:26
Оценка:
Здравствуйте, rg45, Вы писали:

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

R>        MemoryStream _stream;
R>    };
R>


Ваш старый буфер элегантно не освобождается. Освобождается новый после использования.
public void PushInboundMessage(byte[] bytes)
{
    Stream stream;
    stream = this._stream;
Label_0007:
    try
    {
        this._stream = new MemoryStream(bytes);
        goto Label_001F;
    }
    finally
    {
    Label_0015:
        if (stream == null)
        {
            goto Label_001E;
        }
        stream.Dispose();
    Label_001E:;
    }
Label_001F:
    return;
}
Pro
Re[5]: Простенький вопрос к собеседованию
От: hardcase Пират http://nemerle.org
Дата: 18.09.10 07:54
Оценка:
Здравствуйте, Pro100Oleh, Вы писали:

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


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

R>>        MemoryStream _stream;
R>>    };
R>>


PO>Ваш старый буфер элегантно не освобождается. Освобождается новый после использования.

PO>
PO>public void PushInboundMessage(byte[] bytes)
PO>{
PO>    Stream stream;
PO>    stream = this._stream;
PO>Label_0007:
PO>    try
PO>    {
PO>        this._stream = new MemoryStream(bytes);
PO>        goto Label_001F;
PO>    }
PO>    finally
PO>    {
PO>    Label_0015:
PO>        if (stream == null)
PO>        {
PO>            goto Label_001E;
PO>        }
PO>        stream.Dispose();
PO>    Label_001E:;
PO>    }
PO>Label_001F:
PO>    return;
PO>}
PO>



Освобождается. Локальная переменная stream хранит ссылку на предыдущее значение поля _stream.
/* иЗвиНите зА неРовнЫй поЧерК */
Re[9]: Простенький вопрос к собеседованию
От: hardcase Пират http://nemerle.org
Дата: 18.09.10 07:55
Оценка:
Здравствуйте, rg45, Вы писали:

R>Хорошо, допустим, убедили. Как предлагаете решать проблему, с исключениями, описанную мной здесь: Dispose и исключения
Автор: rg45
Дата: 18.09.10
?


А она разве есть?
Контракт IDisposable предполагает то, что метод Dispose не выбрасывает исключений.
А знаете почему? Потому что Dispose может быть вызван в потоке финализатора.
/* иЗвиНите зА неРовнЫй поЧерК */
Re[5]: Простенький вопрос к собеседованию
От: Pro100Oleh Украина  
Дата: 18.09.10 07:57
Оценка:
Вот решение для случая, когда ресурсы класса создаются в конструкторе:

    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                using (var writer = new MyStreamWriter("D:\\file.txt"))
                {
                }

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }
    }

    public class MyStreamWriter : IDisposable
    {
        private System.IO.Stream _stream;

        public MyStreamWriter(string filePath)
        {
            Console.WriteLine("ctor");
            _stream = new System.IO.FileStream(filePath, System.IO.FileMode.Create);
            throw new Exception("oops!");
        }

        ~MyStreamWriter()
        {
            Console.WriteLine("finalizer");
            Dispose(false);
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            Console.WriteLine("dispose");
            _stream = _stream.DisposeIfNotNull();
        }

    }

    public static class Ext
    {
        public static T DisposeIfNotNull<T>(this T obj)
            where T : IDisposable
        {
            if (!object.ReferenceEquals(obj, null))
            {
                obj.Dispose();
            }

            return (T)(object)null;
        }
    }
Pro
Re[6]: Простенький вопрос к собеседованию
От: hardcase Пират http://nemerle.org
Дата: 18.09.10 07:59
Оценка:
Здравствуйте, Pro100Oleh, Вы писали:

PO>Вот решение для случая, когда ресурсы класса создаются в конструкторе:


Финализатор в данном конкретном случае совсем не обязателен, так как из ресурсов у нас только единственный управляемый объект Stream.
/* иЗвиНите зА неРовнЫй поЧерК */
Re[6]: Простенький вопрос к собеседованию
От: Pro100Oleh Украина  
Дата: 18.09.10 08:00
Оценка:
Здравствуйте, hardcase, Вы писали:
H>Освобождается. Локальная переменная stream хранит ссылку на предыдущее значение поля _stream.

Сорри, ступил.
Pro
Re[5]: Простенький вопрос к собеседованию
От: rg45 СССР  
Дата: 18.09.10 08:01
Оценка:
Здравствуйте, Pro100Oleh, Вы писали:

PO>Ваш старый буфер элегантно не освобождается. Освобождается новый после использования.

PO>
PO>public void PushInboundMessage(byte[] bytes)
PO>{
PO>    Stream stream;
PO>    stream = this._stream;
PO>Label_0007:
PO>    try
PO>    {
PO>        this._stream = new MemoryStream(bytes);
PO>        goto Label_001F;
PO>    }
PO>    finally
PO>    {
PO>    Label_0015:
PO>        if (stream == null)
PO>        {
PO>            goto Label_001E;
PO>        }
PO>        stream.Dispose();
PO>    Label_001E:;
PO>    }
PO>Label_001F:
PO>    return;
PO>}
PO>


Двойка Вам. Дизасеммблировать дизасемблировали, а прочесть правильно не можете. Метод Dispose() будет вызван для того, объекта, на который ссылалась переменная this._stream перед входом в блок try-catch, внимание на выделенные строчки.

А если это не достаточно наглядно, то не поленюсь написать пример:
using System;

class SomeDisposable : IDisposable
{
    public string Name;

    public SomeDisposable(string name) { Name = name; }

    public void Dispose() { Console.WriteLine(Name + " is disposed"); }
}

class Program
{
    static void Main(string[] args)
    {
        SomeDisposable someDisposable = new SomeDisposable("First");
        using(someDisposable)
            someDisposable = new SomeDisposable("Second");
    }
}

Output:
First is disposed
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[10]: Простенький вопрос к собеседованию
От: rg45 СССР  
Дата: 18.09.10 08:08
Оценка:
Здравствуйте, hardcase, Вы писали:

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


R>>Хорошо, допустим, убедили. Как предлагаете решать проблему, с исключениями, описанную мной здесь: Dispose и исключения
Автор: rg45
Дата: 18.09.10
?


H>А она разве есть?

H>Контракт IDisposable предполагает то, что метод Dispose не выбрасывает исключений.
H>А знаете почему? Потому что Dispose может быть вызван в потоке финализатора.

Я как бы в курсе, что контракт предполагает. Прочитайте внимательно мой пост, я писал об этом. То, что Dispose не должен сам бросать исключений — это и ежу понятно. А как быть с исключениями, летящими из функций, вызываемых внутри Dispose? Вы предлагаете намертво их глушить и все? А если нет, значит проблема есть, нравится нам это или нет.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[6]: Простенький вопрос к собеседованию
От: Аноним  
Дата: 18.09.10 08:27
Оценка:
Здравствуйте, Pro100Oleh, Вы писали:

PO>Вот решение для случая, когда ресурсы класса создаются в конструкторе:


решение чего? До вызова финализатора FileStream файл не закроется. MyStreamWriter финализтор, кстати, не нужен, тем более, что он неправильно работает.
Re[7]: Простенький вопрос к собеседованию
От: rg45 СССР  
Дата: 18.09.10 08:32
Оценка:
Здравствуйте, Pro100Oleh, Вы писали:

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

PO>Саморазрушение — неудачное слово. Это больше относится к деструктору. Здесь идет речь о освобождении захваченных ресурсов, а их освободить может только класс-хозяин. А Dispose метод должен всегда учитывать случай, что инстанс может быть в неопределенном состоянии.

+1

PO>ЗЫ: Вот только дизайн класса выше мне совсем не нравится.


Я уже согласился, что пример неудачный — он был придуман налету, не подумайте, что из живого проекта. Пример, по которому хотелось бы получить критику находится здесь
Автор: rg45
Дата: 17.09.10
. Только, чтоб сэкономить время, просьба формировать замечания с учетом проблемы, изложенной здесь
Автор: rg45
Дата: 18.09.10
. Ну и кроме того, замечаний типа "мы к такому не привыкли" уже вагон маленькая тележка, а хотелось услышать что-то более существенное.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[10]: Простенький вопрос к собеседованию
От: rg45 СССР  
Дата: 18.09.10 08:42
Оценка:
Здравствуйте, Аноним, Вы писали:

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


R>>Хорошо, допустим, убедили. Как предлагаете решать проблему, с исключениями, описанную мной здесь: Dispose и исключения
Автор: rg45
Дата: 18.09.10
?

А>я считаю, что если один из Dispose кидает исключение, то это как бы совсем плохо и нада падать. не должен Dispose кидать исключения и все тут. ну на мой взгляд это таки да — сродни исключениям в деструкторе С++.
А>в любом случае в случае исключения в одном из Dispose, а потом в одном из следующих (в вашем примере) произойдет утеря исходного исключения (я о исключении в первом Dispose). вот еще реальный пример:
А>
...

А>

А>Результат: System.NotImplementedException: The method or operation is not implemented.


А>что будет если в Disaposable.Dispose кинет исключение? будет утеряно рабочее исключение. совсем не гуд. ошибка как бы есть, но стерта новой (возможно абсолютно неинтересной юзеру типа ArgumentNullException. а что с ним делать? логировать и падать).


Короче говоря, на уровне нашего класса мы эту проблему решать не пытаемся. Правильно я понял мысль? Уповаем на то, что логика приложения верхнего уровня так и реализована — логировать и падать. А что если приложение ведет себя по-другому? Я так понимаю, эту проблему мы тоже на уровне нашего класса не решаем. Ну что ж, не могу сказать что я в восторге, но похоже другого выхода просто нет. Проблему "затирания" одного исключения другим я как-то даже выпустил из виду.

Еще раз спасибо.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[11]: Простенький вопрос к собеседованию
От: Аноним  
Дата: 18.09.10 09:05
Оценка:
Здравствуйте, rg45, Вы писали:

R>Короче говоря, на уровне нашего класса мы эту проблему решать не пытаемся. Правильно я понял мысль? Уповаем на то, что логика приложения верхнего уровня так и реализована — логировать и падать. А что если приложение ведет себя по-другому? Я так понимаю, эту проблему мы тоже на уровне нашего класса не решаем. Ну что ж, не могу сказать что я в восторге, но похоже другого выхода просто нет. Проблему "затирания" одного исключения другим я как-то даже выпустил из виду.

а это все вопрос архитектуры и дизайна. тут нарыл тему
Автор:
Дата: 23.06.10

была еще одна интересная на форуме, большая, основательный срач там был ( ), не нашел к сожалению .

в любом случае, разрабатывая класс, мы должны следовать принципу "Dispose не кидает исключений", либо не юзать FCL и писать все руками подразумевая такую возможность. только все равно не ясно как быть с потерянными исключениями

R>Еще раз спасибо.

да не за что
Re[10]: Простенький вопрос к собеседованию
От: rg45 СССР  
Дата: 18.09.10 09:13
Оценка:
Здравствуйте, Аноним, Вы писали:

А>...

А>что будет если в Disaposable.Dispose кинет исключение? будет утеряно рабочее исключение. совсем не гуд. ошибка как бы есть, но стерта новой (возможно абсолютно неинтересной юзеру типа ArgumentNullException. а что с ним делать? логировать и падать).

Ну и если попытаться подытожить, то типовая реализация метода Dispose должна выглядеть схематично так:
public void Dispose()
{
    try
    {
        disposable1.Dispose();
        disposable2.Dispose();
        disposable3.Dispose();
    }
    catch(Exception innerException)
    {
       throw new FatalError_DoNotCatchThis(innerException);
    }
}

По необходимости можно использовать предложенную в этом топике технологию CheckedDispose. Так?
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[11]: Простенький вопрос к собеседованию
От: Аноним  
Дата: 18.09.10 09:21
Оценка:
Здравствуйте, rg45, Вы писали:

R>
R>public void Dispose()
R>{
R>    try
R>    {
R>        disposable1.Dispose();
R>        disposable2.Dispose();
R>        disposable3.Dispose();
R>    }
R>    catch(Exception innerException)
R>    {
R>       //throw new FatalError_DoNotCatchThis(innerException);
         Environment.FailFast(innerException.Message);
R>    }
R>}
R>

имхо по идее так, НО как мне думается таких проверок делать не нужно, тк писать нужно Dispose так чтобы он не кидал исключений, т.е. не писать там кода который планово может кинуть исключение. в этом случае вызывающий код не ждет исключения того типа, что неожиданно произошло в Dispose вследствии чего его не обрабатывает попадая в AppDomain.UnhandledException ну а дальше логаем и FailFast.

R>По необходимости можно использовать предложенную в этом топике технологию CheckedDispose. Так?

мне она не нравится.
Re[7]: Простенький вопрос к собеседованию
От: _FRED_ Черногория
Дата: 20.09.10 10:59
Оценка:
Здравствуйте, rg45, Вы писали:

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


_FR>>В том-то и паранойя данного вопроса: что он на "понимание" (слово топикстартера), в то время, как умение понимать никак на вопрос ответить не поможет: сгодится лишь "знание" ("пробовал") или "память" ("читал" [спецификацию, имеется в виду, если кто не понял]).


R>Есть один момент, который мне кажется странным в твоих рассуждениях. Почему ты отождествляешь категории "понимать" и "додуматься самому"?


"Понимать" — это термин топикстартера, а не мой

R>Это ведь не одно и тоже.


Не одно.

R>Понимание чего-либо может быть результатом: а) логических рассуждений (додумался сам), б) анализа практического опыта и в) результатом вдумчивого изучения.


Может быть. Но в контексте данного обсуждения поведения using "логические рассуждения" не имеют смысла, ибо в данном случае что бы правильно ответить нужно или "знать" или "угадать". "Угадать" к "понимать" отношения не имеет, а вот "знать" можно или в следствии "практического опыта" (пробовал, как я говорил) или после "вдумчивого изучения" (спецификации языка, как я говорил). Надеюсь, так менее странно звучит.

R>Большинство из нас прекрасно понимают смысл интеграла и производной, но это совсем не означает, что все мы сами до этого додумались. Можно конечно же знать что либо, но при этом не понимать (как теорию относительности, например, или принцип наименьшего действия). Но я счел (это мое ИМХО), что в данном вопросе знание без понимания не имеет особой ценности, поэтому и написал — что вопрос на понимание. Знание также подразумевается, потому что понимать, не зная, вряд ли возможно.


Отличие в том, что в вопросах правил языка различных исключений (то есть "специальных кейсов") достаточно много, чуть ли не столько же, сколько и самих правил. Поэтому полагаться на рассуждение "по аналогии" в вопросе поведения компилятора более чем не надёжно.
Help will always be given at Hogwarts to those who ask for it.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.