Неправильно ли использовать IDisposable и «использовать» как средство для получения «ограниченного поведения» для обеспечения безопасности исключений? - PullRequest
105 голосов
/ 20 января 2010

Что-то, что я часто использовал в C ++, позволяло классу A обрабатывать состояние входа и выхода для другого класса B через конструктор и деструктор A, чтобы убедиться, что если что-то в этой области выдает исключение, тогда B будет иметь известное состояние при выходе из области. Это не чистый RAII, как аббревиатура, но тем не менее, это установленный образец.

В C # я часто хочу сделать

class FrobbleManager
{
    ...

    private void FiddleTheFrobble()
    {
        this.Frobble.Unlock();
        Foo();                  // Can throw
        this.Frobble.Fiddle();  // Can throw
        Bar();                  // Can throw
        this.Frobble.Lock();
    }
}

Что нужно сделать следующим образом

private void FiddleTheFrobble()
{
    this.Frobble.Unlock();

    try
    {            
        Foo();                  // Can throw
        this.Frobble.Fiddle();  // Can throw
        Bar();                  // Can throw
    }
    finally
    {
        this.Frobble.Lock();
    }
}

если я хочу гарантировать состояние Frobble при возврате FiddleTheFrobble. Код будет лучше с

private void FiddleTheFrobble()
{
    using (var janitor = new FrobbleJanitor(this.Frobble))
    {            
        Foo();                  // Can throw
        this.Frobble.Fiddle();  // Can throw
        Bar();                  // Can throw
    }
}

где FrobbleJanitor выглядит примерно как

class FrobbleJanitor : IDisposable
{
    private Frobble frobble;

    public FrobbleJanitor(Frobble frobble)
    {
        this.frobble = frobble;
        this.frobble.Unlock();
    }

    public void Dispose()
    {
        this.frobble.Lock();
    }
}

И вот как я хочу это сделать. Теперь реальность настигает, поскольку для того, что я хочу использовать , требуется , чтобы FrobbleJanitor использовалось с using. Я мог бы посчитать это проблемой проверки кода, но что-то беспокоит меня.

Вопрос: Считается ли вышеупомянутое злоупотреблением using и IDisposable?

Ответы [ 12 ]

1 голос
/ 20 января 2010

Я думаю, вы все сделали правильно. Перегрузка Dispose () была бы проблемой, так как тот же класс позже выполнял очистку, которую он фактически должен был выполнить, и время жизни этой очистки изменилось, чтобы отличаться от времени, когда вы ожидаете удерживать блокировку. Но так как вы создали отдельный класс (FrobbleJanitor), который отвечает только за блокировку и разблокировку Frobble, все достаточно развязано, и вы не столкнетесь с этой проблемой.

Хотя я бы переименовал FrobbleJanitor, вероятно, во что-то вроде FrobbleLockSession.

1 голос
/ 20 января 2010

Это не оскорбительно. Вы используете их для чего они созданы. Но вам, возможно, придется подумать друг о друге в соответствии с вашими потребностями. Например, если вы выбираете «artistry», вы можете использовать «using», но если ваш фрагмент кода выполняется много раз, то из соображений производительности вы можете использовать конструкции «try» .. «finally». Потому что «использование» обычно подразумевает создание объекта.

...