Когда мне нужно управлять управляемыми ресурсами? - PullRequest
4 голосов
/ 15 сентября 2009

Я смотрю на стандартный шаблон Dispose, и мне просто интересно, что мне нужно написать для свободных управляемых ресурсов? Если эти ресурсы уже «управляются», то, конечно, мне не нужно ничего делать.

Если это так, и мой класс не содержит никаких неуправляемых ресурсов (следовательно, нет необходимости его финализации GC), тогда мне нужно только подавить финализацию в моем методе Dispose? : -

public void Dispose()
{
   GC.SuppressFinalize(this);
}

Итак, предположим, что это мой класс:

public sealed class MyClass : IDisposable
{
    IList<MyObject> objects; // MyObject doesn't hold any unmanaged resource
    private bool _disposed;

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    private void Dispose(bool disposing)
    {
        if (!_disposed)
        {  
            // do I need to set the list to null and 
            // call Dispose on each item in the list?
            if (disposing)
            {
                foreach (var o in objects)
                    o.Dispose();

                objects = null;
            }
        }

        _disposed = true;
    }

    ~MyClass()
    {
        Dispose(false);
    }
}

Нужно ли вообще освобождать управляемые ресурсы здесь?

Спасибо

Ответы [ 3 ]

4 голосов
/ 15 сентября 2009

Если ваш класс содержит какие-либо экземпляры IDisposable, вы используете управляемые ресурсы, и поэтому вам следует реализовать IDisposable, чтобы пользователи могли распоряжаться ресурсами. Ваш метод Dispose должен вызывать Dispose на управляемых ресурсах.

Что касается освобождения управляемой памяти, вам не нужно ничего делать. Это обрабатывается GC, но это единственная часть очистки, которая обрабатывается GC. Управляемые и неуправляемые ресурсы должны быть очищены Dispose и / или финализаторами.

Если вы не используете управляемые или неуправляемые ресурсы, вам не нужно реализовывать ни IDisposable, ни финализатор. Реализация финализатора фактически повлияет на производительность вашего типа, поэтому не используйте его, если он вам не нужен.

3 голосов
/ 15 сентября 2009

Вы должны утилизировать любой из управляемых объектов, которые реализуют IDisposable.

Вы не сможете вызвать Dispose для объектов, которые не реализуют IDisposable, поэтому вам нужно проверить это. (Очевидно, что если все возможные экземпляры / потомки MyObject всегда будут реализовывать IDisposable, тогда вам не понадобится эта проверка.)

Нет необходимости устанавливать сам список на null.

В общем случае, я бы, вероятно, переписал цикл, чтобы он выглядел примерно так:

if (disposing)
{
    foreach (var o in objects)
    {
        var d = o as IDisposable;
        if (d != null) d.Dispose();
    }
}

(Кстати, если ваш класс на самом деле не содержит IDisposable объектов или неуправляемых ресурсов, то вам, вероятно, вообще не нужно реализовывать IDisposable или финализатор.)

2 голосов
/ 02 сентября 2015

Есть две причины для реализации IDisposable:
1. Освободить ресурсы под управлением ООН. Этот случай ОЧЕНЬ редок - но, к сожалению, это то, о чем много говорится в документе. Речь идет о том, ЧТО освободить - т.е. избежать утечки ресурсов / памяти.
2. Освободить управляемый ресурс. Это распространено - речь идет НЕ об обеспечении того, что освобождается (потому что управляемые ресурсы всегда будут освобождены в какой-то момент GC), но о том, КОГДА вещи освобождаются . Т.е. он дает пользователю вашего объекта контроль над тем, когда он освобождает управляемые ресурсы (т. Е. Когда закрывает сокеты, файлы и т. Д.), Так что другие вещи могут получить к ним доступ.

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

public virtual void Dispose() {
    foreach (var o in objects) {
        var d = o as IDisposable;
        if (d != null) d.Dispose();
    }
}
...