Правильное размещение иерархии объектов в C #

Я работаю над проектом, в котором определенная иерархия классов реализует IDisposable.

Некоторые классы также реализуют метод Finalize (~ MyClass ())

В целом это выглядит примерно так:

public class BaseClass : IDisposable
{
}

public class SomeClass : BaseClass
{
    ~SomeClass()
    {
        Dispose();
    }

    Dispose()
    {
        // Do some stuff.
        base.Dispose();
    }
}

public class AnoterClass : SomeClass
{
    ~AnoterClass()
    {
        Dispose();
    }

    Dispose()
    {
        // Do some stuff.
        base.Dispose();
    }
}

Я хотел бы знать, как правильно обрабатывать вызовы Dispose, поскольку кажется, что эти объекты удаляются с помощью вызова Dispose (), а затем сбоя, поскольку вызывается метод Finalize.

Лучше ли держать флаг в самом низком классе в иерархии (защищенный bool удален) и проверять это на каждом уровне иерархии классов?

Я считаю, что каждое возможное решение требует некоторого дублирования кода, а это не то, что мне нужно.


person lysergic-acid    schedule 20.10.2012    source источник
comment
Сложная иерархия, содержащая неуправляемые ресурсы, кажется странной. Вероятно, вам следует хранить неуправляемые ресурсы в простых SafeHandle и избегать финализаторов в вашем сложном графе объектов.   -  person CodesInChaos    schedule 20.10.2012


Ответы (2)


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

Образец, которому нужно следовать, находится здесь

Редактировать:

Я думаю, что вам нужно реализовать на определенном уровне иерархии классов, только если у вас есть что-то новое, что нужно удалить на этом уровне, в противном случае я считаю, что удаление в базовом классе сделает все, что вам нужно. Если ваша реализация в каком-либо конкретном классе просто вызывает base.Dispose(disposing), тогда это не нужно, если она должна выполнить некоторую чистую uop, тогда вызовите base.Dispose(), тогда она вам понадобится.

Наличие защищенного флага, как вы предлагаете, должно быть нормальным.

person Sam Holder    schedule 20.10.2012
comment
Спасибо. Я знаком с шаблоном, вопрос в том, должен ли он быть реализован на всех уровнях иерархии классов? Нет более простого варианта? - person lysergic-acid; 20.10.2012
comment
Вы должны обновить свои примеры шаблоном, который вы фактически используете в качестве причины, по которой вы получаете сбой, потому что вы не реализуете шаблон правильно и не подавляете вызов сборщика мусора к методу finalize после того, как вы удалили его вручную. - person Sam Holder; 20.10.2012

Если ваш базовый класс реализует стандартный шаблон IDisposable, все, что вам нужно сделать, это добавить переопределение Dispose(bool disposing) к каждому производному классу, который сам владеет IDisposable или неуправляемыми ресурсами:

protected override void Dispose(bool disposing)
{
    try
    {
        if (disposing)
        {
            // Release managed resources
        }
        // Release unmanaged resources
    }
    finally
    {
        base.Dispose(disposing);
    }
}

Не следует реализовывать финализаторы ни в одном из производных классов.

И, конечно же, любые классы в иерархии, не имеющие собственных IDisposable ресурсов, не нуждаются в этом переопределении.

person Joe    schedule 20.10.2012
comment
+1 за более четкое описание и пример того, что я пытался сказать! - person Sam Holder; 20.10.2012
comment
Если вся цель класса не сосредоточена вокруг неуправляемого ресурса, вероятно, не должно быть финализаторов в любых классах в его иерархии. Вместо этого любой ресурс, которому потребуется очистка на основе финализации, должен быть инкапсулирован в его собственный объект, цель которого сосредоточена вокруг этого ресурса. Если финализатор объекта не подавлен, это приведет к тому, что каждый объект, на который он содержит прямую или косвенную сильную ссылку, будет оставаться активным для другого цикла сборки мусора. Таким образом, финализируемые объекты должны избегать хранения ссылок на внешние объекты, которые не требуются для очистки. - person supercat; 23.10.2012