Как объекты IDisposable передаются аргументам базового конструктора в C #, если инициализация не удалась? - PullRequest
4 голосов
/ 20 октября 2010

Если я передаю объект IDisposable конструктору базового класса, используя конструкцию base(...), я вызываю глупую ошибку в FxCop о выпуске IDisposable. Это предупреждение иногда полезно в других местах, поэтому я не хочу его отключать, но я понимаю, что не знаю точную семантику, которую мне следует использовать.

Является ли обязанностью базового конструктора обернуть свое тело в попытке / перехватить, чтобы гарантировать, что вещь IDisposable будет правильно утилизирована в случае исключения?

Похожие вопросы:

Ответы [ 4 ]

4 голосов
/ 20 октября 2010

Не совсем ответ на вопрос, но ...

Вам не обязательно полностью отключать правило - вы можете подавить его для методов, в которых вы знаете, что анализ чрезмерно усердствует:

[SuppressMessage("Microsoft.Reliability",
                 "CA2000:DisposeObjectsBeforeLosingScope",
                 Justification = "Your reasons go here")]
public YourClass(IDisposable obj) : base(obj)
{
}

Хотя анализ CA2000 , поэтому сломан, так что было бы более полезно отключить его вообще.

2 голосов
/ 20 октября 2010

Да, ни конструктор класса, ни оператор using не вызывают Dispose в случае исключения в конструкторе.

Ваша задача - обрабатывать исключения в конструкторе, потому что объект, который еще не создан, нельзя «утилизировать» так же, как успешно созданный.для базового конструктора, это большая проблема:

class A: IDisposable
{
    public A() // constructor
    {
        r1 = new Resource(res1_id);     // resource aquisition 
        r2 = new Resource(res2_id);     // assume exception here
    }

    public void Dispose()
    {
        r1.Release();           // released successfully
        r2.Release();           // what to do?
    }

    Resource r1, r2;
}
1 голос
/ 20 октября 2010

Простое правило, которому нужно следовать: если вы создаете * это, вы несете ответственность за его удаление. И наоборот, если метод (будь то конструктор или другой) не создает одноразовый объект, я не ожидал бы, что он избавится от него. (* Создание включает в себя вызов методов, которые возвращают IDisposable.)

Итак, что-то вроде

public Foo(SomeDisposable obj) : base(obj) { }

Я бы ожидал увидеть что-то вроде

using (SomeDisposable obj = new SomeDisposable())
{
    Foo foo = new Foo(obj);
}

а не

Foo foo = new Foo(new SomeDisposable());

Если у вас есть конструктор без параметров для Foo и вы хотите вызвать базовый конструктор с помощью одноразового объекта, вы попадаете в более хитрое положение, и, вероятно, именно в этом состоит правило, пытаясь защитить вас. , Я бы сказал, избегайте такой позиции, либо кодируя базу для создания и, следовательно, отвечая за IDisposable, либо создавайте отображение 1: 1 между конструкторами с параметрами IDisposable, чтобы Foo без параметров не вызывал параметризованную базу.

Но метод или конструктор не должны догадываться, что вы закончили с объектом, который передали, потому что как он должен знать? Вы могли бы использовать его для других целей.

0 голосов
/ 22 октября 2010

Я пришел с хорошим шаблоном, который я опубликовал в ответ на свой собственный связанный вопрос здесь , который позволяет безопасно комбинировать объявление и инициализацию полей iDisposable и гарантировать, что они располагаютсякогда конструктор терпит неудачу.В коде можно использовать небольшую очистку, но, кажется, здесь уместно.

Единственное, что я не могу понять, как это сделать, так это включить настройку / очистку событий.Наличие списка объектов, которые были распределены, не переводится в список подписок на события, которые необходимо развернуть, даже путем отражения.

...