Нетрадиционное использование using и IDisposable
Предположим, что у нас есть форма и на ней кнопка, по нажатию на которую выполняется некая долгоиграющая операция. При выполнении длительных операций в главном потоке приложения, как правило, надо изменить курсор мыши на песочные часы и затем восстановить его.
private void button1_Click(object sender, EventArgs e)
{
Cursor oldCursor = Cursor.Current;
try
{
Cursor.Current = Cursors.WaitCursor;
// do something time consuming
DoSomethingTimeConsuming();
}
finally
{
Cursor.Current = oldCursor;
}
}
Хочу обратить внимание, что конструкция try finally необходима, что бы в случае необработанного исключения в DoSomethingTimeConsuming все равно восстановить курсор. Однако у данного обработчика есть несколько недостатков:
- конструкция достаточно объемна
- необходимость блока try finally не очевидна и поэтому блок можно забыть.
- данный код приходится дублировать для каждого подобного обработчика.
У меня есть небольшой трюк, который выполняет ту же работу но не содержит выше перечисленные недостатки. Новый вариант обработчика будет выглядеть следующим образом:
private void button2_Click(object sender, EventArgs e)
{
using (WaitCursor wch = new WaitCursor())
{
// do something time consuming
DoSomethingTimeConsuming();
}
}
Теперь код обработчика кнопки, по управлению курсором мыши стал намного меньше, а работа по управлению курсором мыши перешла в класс WaitCursor и не будет дублироваться при создании новых обработчиков.
Код для класса WaitCursor:
internal class WaitCursor: IDisposable
{
private Cursor m_OldCursor;
internal WaitCursor()
{
m_OldCursor = Cursor.Current;
Cursor.Current = Cursors.WaitCursor;
}
public void Dispose()
{
Cursor.Current = m_OldCursor;
}
}
Использование using приводит к тому что блок try finally будет сгенерирован автоматически. Так же автоматически конструкцией using будет вызван метод WaitCursor. Dispose, который и восстановит курсор.
Хочу отметить, что подобный механизм можно использовать не только для управления курсором.
Комментарии
Использование статик свойства Cursor.Current не всегда оправдано.
В CLR via C# было это описано
что именно?