Страницы

Поиск по вопросам

вторник, 25 февраля 2020 г.

Класс устанавливающий курсор ожидания и автоматически сбрасывающий его

#c_sharp #winforms


Создал вот такой класс:

class CursorEx: IDisposable
{
    public CursorEx()
    {
        Cursor.Current = Cursors.WaitCursor;
    }
    public void Dispose()
    {
        Cursor.Current = Cursors.Default;
    }
}


Использую вот так:

public void Method()
{
    new CursorEx();
    //Здаесь что-то выполняется
}


Подразумевается, что после выполнения метода, вызовется метод Dispose() и курсор
установится на дефолтный.
Могут ли быть какие-то варианты, когда произойдет сбой?
    


Ответы

Ответ 1



Во-первых, вы забыли вызвать Dispose. Для этого следует использовать using: using (new CursorEx()) { // что-то выполняется } На сборку мусора полагаться нельзя, она вызывается недетерминированно в любой момент после пропадания объекта из области видимости. Во-вторых, вы не восстанавливаете исходный курсор. Если какая-то функция изменяет курсор, а затем вызывает функцию, которая тоже изменяет курсор, то курсор будет восстановлен уже после возврата из первой функции: using (new CursorEx()) { using (new CursorEx()) { // что-то выполняется } // курсор уже восстановлен } // курсор должен был быть восстановлен здесь Вам следует сохранять текущий курсор в конструкторе и восстанавливать его в Dispose. В-третьих, можно избавиться от лишнего объекта в памяти, если заменить класс на структуру. Итого: public struct CursorWaiter : IDisposable { private readonly Cursor _originalCursor; public CursorWaiter (Cursor newCursor = null) { _originalCursor = Cursor.Current; Cursor.Current = newCursor ?? Cursors.WaitCursor; } public void Dispose () { Cursor.Current = _originalCursor; } } Из комментариев: этот код рассчитан на то, что программист будет использовать тип только с помощью using, не будет уничтожать объект по несколько раз, не будет копировать и т.п. Если есть сомнения в этом, то нужно добавить проверку на повторный вызов Dispose (с помощью отдельного флага или обнуления _originalCursor), а также заменить класс на структуру для избавления он возможности копирования или вовсе скрыть тип за методом с лямбдой.

Ответ 2



Конечно. Это вообще хоть раз сработало? Вы неверно пользуетесь сборкой мусора, .NET работает сосвсем не так, как C++. Объект будет уничтожен не в конце метода, а когда захочется сборщику мусора. Поскольку у вас нет на него ссылок, то он может вообще быть уничтожен сразу после создания. А метод Dispose вообще не будет вызван автоматически, IDisposable для рантайма никакого специального значения не имеет. Делайте так: public void Method() { using (new CursorEx()) { //Здаесь что-то выполняется } } И обязательно разберитесь со временем жизни объектов в .NET, без этого никуда.

Комментариев нет:

Отправить комментарий