Как утилизировать объект только при возникновении исключения? - PullRequest
1 голос
/ 11 октября 2011

Я создаю экземпляр одноразового объекта (в моем случае FileStream) в своем конструкторе, и мне нужно поработать над ним. Однако это может вызвать любое количество разных исключений. Теперь я даже не хочу слишком много возиться с этими исключениями и хочу, чтобы они распространялись до вызывающей стороны. Однако мне нужно сначала избавиться от объекта. Каков наилучший способ сделать это? Прямо сейчас я могу думать только о чем-то таком:

IDisposable disposableObject = InstantiateDisposable();
bool error = false;
try
{
    DoWork(disposableObject);
}
catch (ReallyBadException e)
{
    error = true;
    throw new EvenWorseException("some message", e);
}
catch (Exception)
{
    error = true;
    throw;
}
finally
{
    if (error) disposableObject.Dispose();
}

Это даже правильно или Dispose () будет пропущен в некоторых особых случаях? Есть ли более простой способ сделать это? Это становится немного громоздким, если вам нужно по отдельности перехватить кучу различных исключений по какой-либо причине, и вам всегда нужно копировать и вставлять этот error = true; бит.

Edit: Просто чтобы уточнить: мне нужно избавиться от объекта только в случае DoWork() сбой / выброс исключения. Если этот метод завершится успешно, я пока не хочу избавляться от объекта, так как в дальнейшем будет больше работы с ним.

Ответы [ 6 ]

6 голосов
/ 11 октября 2011

Почему бы не инвертировать логику?

IDisposable disposableObject = InstantiateDisposable();
bool error = true;
try
{
    DoWork(disposableObject);
    error = false; // if it gets to this line, no exception was thrown
}
catch (ReallyBadException e)
{        
    throw new EvenWorseException("some message", e);
}    
finally
{
    if (error) disposableObject.Dispose();
}
2 голосов
/ 11 октября 2011
IDisposable disposable = InstantiateDisposable();
try
{
    try
    {
        DoWork(disposable);
    }
    catch (Exception)
    {
        disposable.Dispose();
        throw;
    }
}
catch (ReallyBadException ex)
{
    throw new EvenWorseException("some message", ex);
}

Хотя, на самом деле, если вы не возвращаете объект или не сжимаете его для чего-то, вы должны использовать блок using и всегда располагать им.

2 голосов
/ 11 октября 2011

Не пытайтесь «обрабатывать» исключения, с которыми вы ничего не можете поделать.

Если у вас нет явной пользы от регистрации диагностики или повторного вызова другого типа, простопусть он провалится и выпустит «одноразовый объект» в предложении «наконец»!

Многие люди слишком запутываются или делают бессмысленные гадости, когда дело доходит до обработки исключений.Вы должны получить след, когда он выходит внизу.Нет смысла в «лови и немедленно перебрасывай».

IDisposable disposableObject = InstantiateDisposable();
bool error = true;
try {
    DoWork(disposableObject);
    error = false; // if it gets to this line, no exception was thrown

} finally {
    if (error) disposableObject.Dispose();
}

Надеюсь, это поможет!

0 голосов
/ 18 апреля 2019

Как насчет обертывания внутри такого служебного объекта?

class Disposer : IDisposable
{
    private IDisposable target;

    public Disposer(IDisposable target)
    {
        this.target = target;
    }

    public void Cancel()
    {
        this.target = null;
    }

    public void Dispose()
    {
        this.target?.Dispose();
        Cancel();
    }
}

Это эквивалентно управлению bool error флагом, но, возможно, немного чище, если вам нравится using:

IDisposable disposableObject = InstantiateDisposable();
using (Disposer disposer = new Disposer(disposableObject))
{
    try
    {
        DoWork(disposableObject);
        disposer.Cancel();
    }
    catch (ReallyBadException e)
    {
        throw new EvenWorseException("some message", e);
    }
}

// ... continue with disposableObject
0 голосов
/ 11 октября 2011

Почему бы не Dispose в catch?

IDisposable disposableObject = InstantiateDisposable();

try
{
    DoWork(disposableObject);
}
catch (ReallyBadException e)
{
    disposableObject.Dispose();
    throw new EvenWorseException("some message", e);
}
catch (Exception)
{
    disposableObject.Dispose();
    throw;
}
0 голосов
/ 11 октября 2011

Есть ли причина, по которой вы не выбрасываете объект, когда нет ошибки? Вы, вероятно, должны быть!

Использование стандартного шаблона using означает, что ваш объект всегда будет безопасно утилизирован, и тогда вам нужно только беспокоиться о перехвате любых исключений - например, ReallyBadException - которые требуют особого внимания , Любые другие исключения будут сообщать вызывающему абоненту.

using (IDisposable disposableObject = InstantiateDisposable())
{
    try
    {
        DoWork(disposableObject);
    }
    catch (ReallyBadException e)
    {
        throw new EvenWorseException("some message", e);
    }
}
...