Я считаю, что это злоупотребление оператором using. Знаю, что на этой должности я нахожусь в меньшинстве.
Я считаю это злоупотреблением по трем причинам.
Во-первых, потому что я ожидаю, что "using" используется для использования ресурса и удаления его, когда вы закончите с ним. Изменение состояния программы - это не использование ресурса, а его обратное изменение ничего не уничтожение. Следовательно, «использование» для изменения и восстановления состояния является злоупотреблением; код вводит в заблуждение случайного читателя.
Во-вторых, потому что я ожидаю, что «использование» будет использоваться из вежливости, а не по необходимости. Причина, по которой вы используете "using" для удаления файла по завершении работы с ним, заключается не в том, что это необходимо, а в том, что это вежливо - кто-то еще может ждать, чтобы использовать этот файл, поэтому сказать «готово» - это морально правильный поступок. Я ожидаю, что я смогу провести рефакторинг «using», чтобы использованный ресурс удерживался дольше и утилизировался позже, и что единственное влияние этого - это небольшое неудобство для других процессов . Блок «using», который имеет семантическое влияние на состояние программы, является оскорбительным, потому что он скрывает важную, необходимую мутацию состояния программы в конструкции, которая выглядит так, как будто это сделано для удобства и вежливости, а не по необходимости.
И в-третьих, действия вашей программы определяются ее состоянием; необходимость осторожного манипулирования состоянием - вот почему мы впервые ведем этот разговор. Давайте рассмотрим, как мы могли бы проанализировать вашу исходную программу.
Если бы вы принесли это на проверку кода в моем офисе, первый вопрос, который я бы задала, будет: «Действительно ли правильно блокировать блокировку при возникновении исключения?» Из вашей программы совершенно очевидно, что эта штука агрессивно повторно блокирует блокировку, что бы ни случилось. Верно? Возникло исключение. Программа находится в неизвестном состоянии. Мы не знаем, выбросили ли Foo, Fiddle или Bar, почему они выбросили или какие мутации они произвели в другом состоянии, которое не было очищено. Сможете ли вы убедить меня, что в этой ужасной ситуации всегда правильно сделать повторную блокировку?
Может быть, а может и нет. Я хочу сказать, что с исходным кодом рецензент знает, что нужно задать вопрос. С кодом, который использует "using", я не знаю, как задать вопрос; Я предполагаю, что блок «using» выделяет ресурс, использует его в течение некоторого времени и вежливо избавляется от него, когда это будет сделано, а не потому, что закрывающая скобка блока «using» изменяет состояние моей программы в исключительной ситуации, когда было нарушено произвольно много условий согласованности состояния программы.
Использование блока "using" для семантического эффекта делает этот фрагмент программы:
}
чрезвычайно значимый. Когда я смотрю на эту единственную закрывающую скобу, я не сразу думаю, что «эта скобка имеет побочные эффекты, которые имеют далеко идущие последствия для глобального состояния моей программы». Но когда вы так злоупотребляете «использованием», внезапно это происходит.
Второе, что я бы спросил, если бы увидел ваш исходный код: «Что произойдет, если после разблокировки, но до того, как будет введена попытка, будет выброшено исключение?» Если вы запускаете неоптимизированную сборку, компилятор мог вставить инструкцию no-op перед попыткой, и может произойти исключение прерывания потока на no-op. Это редко, но в реальной жизни случается, особенно на веб-серверах. В этом случае разблокировка происходит, но блокировки никогда не происходит, потому что исключение было сгенерировано до попытки. Вполне возможно, что этот код уязвим для этой проблемы и действительно должен быть написан
bool needsLock = false;
try
{
// must be carefully written so that needsLock is set
// if and only if the unlock happened:
this.Frobble.AtomicUnlock(ref needsLock);
blah blah blah
}
finally
{
if (needsLock) this.Frobble.Lock();
}
Опять же, может быть, а может и нет, но я знаю, что нужно задать вопрос. С версией "using" он подвержен той же проблеме: исключение прерывания потока может быть сгенерировано после того, как Frobble заблокирован, но до того, как будет введена область с защитой от попытки, связанная с использованием. Но с версией "с использованием" я предполагаю, что это "ну и что?" ситуация. Очень жаль, если это произойдет, но я предполагаю, что «использование» используется только для вежливости, а не для изменения жизненно важного состояния программы. Я предполагаю, что если какое-то ужасное исключение прерывания потока произойдет точно в неподходящее время, тогда, ну что ж, сборщик мусора в конечном итоге очистит этот ресурс, запустив финализатор.
person
Eric Lippert
schedule
20.01.2010