Здравствуйте, _FRED_, Вы писали:
_FR>Сомневаюсь, что вопрос "на понимание". Скорее "на знание" (пробовал\не пробовал) или "на память" (читал\не читал).
Да про такое даже прочитать где-то сложно, так что в практической надобности такого вопроса я сомневаюсь. Лично я бы конечно заподозрил и ответил, что нет, но не был бы точно уверен почему.
Сейчас специально открыл Рихтера, Албахари и спецификацию C# и нигде не нашел описания такого случая. Так что если надо кого-то завалить на собеседовании и почувствовать своё превосходство, то да, вопрос хороший.
Здравствуйте, _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.
Здравствуйте, 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
};
И знать это нужно не для того чтоб кого-то завалить и показать свое превосходство, а в первую очередь для того, чтоб правильно и эффективно использовать предоставляемые платформой и языком возможности.
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, _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>А спрашивать о том, что произойдёт, когда компилятор это сам скажет, не должно.
Да, это результат того, что пример был максимально упрощен. Если заменить локальную переменную на поле класса, то компилятор уже не выдает такого предупреждения (пример здесь
R> // Вот так элегантно освобождается старый буфер и создается новый
R> using (_stream)
R> _stream = new MemoryStream(bytes);
R> ...
R> using (_stream)
R> { }
R>
Здравствуйте, rg45, Вы писали:
R>Да, это результат того, что пример был максимально упрощен. Если заменить локальную переменную на поле класса, то компилятор уже не выдает такого предупреждения (пример здесь
идея не ясна. потрудитесь донести ее более доходчиво. зачем сие, для чего такое знание, и где такое используется? приведенный пример не прошел бы code review в большинстве компаний
Здравствуйте, 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.
Здравствуйте, 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 и должен при своем разрушении освободить все агрегированные объекты...
но конструктор не отработал, значит экземпляр класса не создан. должен ли он заниматся саморазрушением? имхо вопрос тут в архитектуре...
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, rg45, Вы писали:
R>>Соглашусь, пример не очень удачный и возникшие вопросы закономерны. Что скажете на счет такого: допустим, есть фасадный класс, инкапсулируюший в себе несколько объектов, реализующих интерфейс IDisposable. Сам фасадный класс также реализует интерфейс IDisposable и должен при своем разрушении освободить все агрегированные объекты...
А>но конструктор не отработал, значит экземпляр класса не создан. должен ли он заниматся саморазрушением? имхо вопрос тут в архитектуре...
Он успел создать некоторые объекты, реализующие интерфейс IDisposable. И если он их не разрушит то это чревато утечками системных ресурсов — неуправляемой памяти, объектами ядра, подвисшими потоками и даже процессами. Ведь понятие системных ресурсов несколько шире, выделение и освобождение памяти и освобождение далеко не всех ресурсов по зубам сборщику мусора.
--
Не можешь достичь желаемого — пожелай достигнутого.
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 придуман был.
Здравствуйте, _FRED_, Вы писали:
_FR>Сомневаюсь, что вопрос "на понимание". Скорее "на знание" (пробовал\не пробовал) или "на память" (читал\не читал).
Вот тут не соглашусь. Как-то проблем с ответом не возникло ни у меня, ни у коллег — хотя и не пробовал никто такого. Наверное каждый кто пытался представить во что будет разворачиваться using конструкция ответит без проблем.
Однако зачем такое спрашивать на собеседовании не пойму. Что покажет ответ на этот вопрос? Тогда уже лучше сразу попросить написать эквивалент using — по крайней мере покажет что человек не угадывал, а понимает как оно работает.