Пожизненная проблема неуправляемых ресурсов IDisposable в диаграмме составного объекта?

Этот вопрос о контакте со (взаимодействующими с COM) неуправляемыми ресурсами и проверка, что там не будут никакие утечки ресурсов. Я ценил бы обратную связь на том, делаю ли я, кажется, вещи правильный путь.

Фон:


Скажем, у меня есть два класса:

  • Класс LimitedComResource который является оберткой вокруг COM-объекта (полученный через некоторый API). Может только быть ограниченное количество тех COM-объектов, поэтому мой класс реализует IDisposable интерфейс, который будет ответственен за выпуск COM-объекта, когда он больше не будет необходим.

  • Объекты другого типа ManagedObject временно создаются для выполнения некоторой работы над a LimitedComResource. Они не IDisposable.

Для суммирования вышеупомянутого в схеме мои классы могли бы быть похожими на это:

            +---------------+           +--------------------+
            | ManagedObject | <>------> | LimitedComResource |
            +---------------+           +--------------------+
                                                  |
                                                  o IDisposable

(Я обеспечу пример кода для этих двух классов через только момент.)

Вопрос:


Начиная с моего временного файла ManagedObject объекты не доступны, я, очевидно, не имею никакого контроля, сколько времени они будут вокруг. Однако тем временем я мог бы иметь Disposed LimitedComObject это a ManagedObject относится к. Как я могу удостовериться это a ManagedObject не получит доступ к a LimitedComResource это больше не там?

            +---------------+           +--------------------+
            | managedObject | <>------> |   (dead object)    |
            +---------------+           +--------------------+

Я в настоящее время реализовывал это с соединением слабых ссылок и флага в LimitedResource который сигнализирует, был ли объект уже расположен. Есть ли какой-либо лучший путь?

Пример кода (что я в настоящее время получал):


LimitedComResource:

class LimitedComResource : IDisposable
{
    private readonly IUnknown comObject;  // <-- set in constructor

    ...

    void Dispose(bool notFromFinalizer)
    {
        if (!this.isDisposed)
        {
            Marshal.FinalReleaseComObject(comObject);
        }
        this.isDisposed = true;
    }

    internal bool isDisposed = false;
}

ManagedObject:

class ManagedObject
{
    private readonly WeakReference limitedComResource;  // <-- set in constructor

    ...

    public void DoSomeWork()
    {
        if (!limitedComResource.IsAlive())
        {
            throw new ObjectDisposedException();
            //        ^^^^^^^^^^^^^^^^^^^^^^^
            //  is there a more suitable exception class?
        }

        var ur = (LimitedComResource)limitedComResource.Target;
        if (ur.isDisposed)
        {
            throw new ObjectDisposedException();
        }

        ...  // <-- do something sensible here!
    }
}
1
задан stakx 29 April 2010 в 21:41
поделиться

2 ответа

Нет, это не нормально. WeakReference только сообщает вам, что управляемый объект получил сборщик мусора. Что не имеет ничего общего с IDisposable. Задача Dispose () - освободить неуправляемые ресурсы до того, как это сделает сборщик мусора.

На самом деле, у вас серьезная проблема, если управляемый объект находится в поколении №1, а оболочка COM - в поколении №0. WeakReference не может поддерживать обертку в живых, она будет собрана, а COM-объект удален до того, как у вас появится возможность самостоятельно вызвать Dispose ().

Просто сохраните простую ссылку на объект-оболочку в вашем управляемом объекте. Вы можете установить для него значение null после вызова Dispose (), чтобы оболочка могла быть собрана. И выбросить ObjectDisposedException, если клиентский код пытается его использовать, а ссылка равна нулю. Или воссоздайте его, если в этом есть смысл.

1
ответ дан 3 September 2019 в 00:56
поделиться

Когда вы приводите цель слабой ссылки к типу объекта, она возвращает null, если объект был утилизирован. Просто проверьте, не является ли возвращаемое значение null, прежде чем выполнять с ним операции. Смотрите пример в документации. Возможно, вам также пригодится эта статья Использование слабых ссылок. Вот соответствующая цитата из последней статьи:

Чтобы установить сильную ссылку и использовать объект снова, приведите свойство Target свойства WeakReference к типу объекта. Если свойство Target возвращает null, объект был собран; в противном случае вы можете продолжать использовать объект, потому что приложение восстановило сильную ссылку на него.

Пример:

class ManagedObject 
{ 
    private readonly WeakReference limitedComResource;  // <-- set in constructor 

    ... 

    public void DoSomeWork() 
    { 
        var ur = (LimitedComResource)limitedComResource.Target; 
        if (ur == null) 
        { 
            throw new ObjectDisposedException(); 
        } 

        ...  // <-- do something sensible here! 
    } 
}
1
ответ дан 3 September 2019 в 00:56
поделиться
Другие вопросы по тегам:

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