Сведения о вопросе

Oleksandr

11:58, 15th August, 2020

Теги

.net   memory   dispose    

Как избавиться от класса в .net?

Просмотров: 610   Ответов: 20

Сборщик мусора .NET в конечном итоге освободит память, но что делать, если вы хотите, чтобы эта память немедленно вернулась? Какой код нужно использовать в классе MyClass для вызова

MyClass.Dispose()

и освободить все используемое пространство переменными и объектами в MyClass ?



  Сведения об ответе

SILA

09:38, 17th August, 2020

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

Ссылки, указывающие на GC.Collect(), являются правильным ответом, хотя использование этой функции обычно не рекомендуется документацией Microsoft .NET.

Edit: заработав значительную сумму кармы за этот ответ, я чувствую определенную ответственность за его разработку, чтобы новичок в управлении ресурсами .NET не получил неверного впечатления.

Внутри процесса .NET существует два вида ресурсов-управляемые и неуправляемые. "Managed" означает, что среда выполнения контролирует ресурс, в то время как "unmanaged" означает, что это ответственность программиста. И на самом деле есть только один вид управляемого ресурса, который мы сегодня заботимся в .NET-память. Программист говорит среде выполнения выделить память, и после этого она должна выяснить, когда память может быть освобождена. Механизм, который использует .NET для этой цели, называется сборкой мусора , и вы можете найти много информации о GC в интернете, просто используя Google.

Что касается других видов ресурсов, то .NET ничего не знает об их очистке, поэтому ему приходится полагаться на программиста, чтобы сделать правильный выбор. Для этого платформа предоставляет программисту три инструмента:

  1. Интерфейс IDisposable и оператор "using" в VB и C#
  2. Метод завершения
  3. Шаблон IDisposable, реализованный многими классами BCL

Первый из них позволяет программисту эффективно приобретать ресурс, использовать его и затем выпускать все это в рамках одного и того же метода.

using (DisposableObject tmp = DisposableObject.AcquireResource()) {
    // Do something with tmp
}
// At this point, tmp.Dispose() will automatically have been called
// BUT, tmp may still a perfectly valid object that still takes up memory

Если "AcquireResource"-это фабричный метод, который (например) открывает файл, а "Dispose" автоматически закрывает файл, то этот код не может пропускать файловый ресурс. Но память для самого объекта "tmp" вполне может быть выделена. Это потому, что интерфейс IDisposable не имеет абсолютно никакого отношения к сборщику мусора. Если вы действительно хотите убедиться, что память была освобождена, единственным вариантом будет вызвать GC.Collect() для принудительной сборки мусора.

Однако нельзя не подчеркнуть, что это, вероятно, не очень хорошая идея. Обычно гораздо лучше позволить сборщику мусора делать то, для чего он был создан, а именно управлять памятью.

Что происходит, если ресурс используется в течение более длительного периода времени, так что его продолжительность жизни пересекает несколько методов? Очевидно, что оператор "using" больше не применим, поэтому программисту придется вручную вызвать "Dispose", когда он или она закончит работу с ресурсом. А что будет, если программист забудет? Если нет никакого запасного варианта, то процесс или компьютер могут в конечном итоге исчерпать тот ресурс, который не был должным образом освобожден.

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

Таким образом, в случае файла нам теоретически не нужно закрывать файл вручную вообще. Мы можем просто подождать, пока сборщик мусора доберется до него, а затем позволить финализатору сделать работу. К сожалению, это не работает хорошо на практике, потому что сборщик мусора работает недетерминированно. Файл может оставаться открытым значительно дольше, чем ожидает программист. И если достаточное количество файлов остается открытым, система может потерпеть неудачу при попытке открыть дополнительный файл.

Для большинства ресурсов мы хотим получить и то, и другое. Мы хотим, чтобы соглашение было в состоянии сказать "we're done with this resource now", и мы хотим убедиться, что есть по крайней мере некоторый шанс для очистки произойдет автоматически, если мы забудем сделать это вручную. Вот где в игру вступает паттерн "IDisposable". Это соглашение, которое позволяет IDispose и финализатору хорошо играть вместе. Вы можете увидеть, как работает шаблон, взглянув на официальную документацию для IDisposable .

Итог: Если вы действительно хотите просто убедиться, что память освобождена, то IDisposable и финализаторы вам не помогут. Но интерфейс IDisposable является частью чрезвычайно важного паттерна, который должны понимать все программисты .NET.


  Сведения об ответе

SKY

19:55, 18th August, 2020

Вы можете утилизировать только экземпляры, реализующие интерфейс IDisposable.

Чтобы заставить сборщик мусора немедленно освободить (неуправляемую) память:

GC.Collect();  
GC.WaitForPendingFinalizers();

Обычно это плохая практика, но есть, например, ошибка в x64-версии фреймворка .NET, которая заставляет GC вести себя странно в некоторых сценариях, и тогда вы можете захотеть сделать это. Я не знаю, была ли ошибка уже решена. Кто-нибудь знает?

Чтобы избавиться от класса вы делаете это:

instance.Dispose();

или вот так:

using(MyClass instance = new MyClass())
{
    // Your cool code.
}

это будет переведено во время компиляции на:

MyClass instance = null;    

try
{
    instance = new MyClass();        
    // Your cool code.
}
finally
{
    if(instance != null)
        instance.Dispose();
}

Вы можете реализовать интерфейс IDisposable следующим образом:

public class MyClass : IDisposable
{
    private bool disposed;

    /// <summary>
    /// Construction
    /// </summary>
    public MyClass()
    {
    }

    /// <summary>
    /// Destructor
    /// </summary>
    ~MyClass()
    {
        this.Dispose(false);
    }

    /// <summary>
    /// The dispose method that implements IDisposable.
    /// </summary>
    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    /// <summary>
    /// The virtual dispose method that allows
    /// classes inherithed from this one to dispose their resources.
    /// </summary>
    /// <param name="disposing"></param>
    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                // Dispose managed resources here.
            }

            // Dispose unmanaged resources here.
        }

        disposed = true;
    }
}


  Сведения об ответе

crush

09:40, 7th August, 2020

Ответы на этот вопрос стали более чем немного запутанными.

Название спрашивает об утилизации, но затем говорит, что они хотят немедленно вернуть память.

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

.Net решает, когда лучше очистить и освободить память, а не вы как кодер .Net.

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

В принципе .Net действительно соберет память обратно, когда это будет проще всего сделать - он очень хорошо решает, когда именно. Если вы не пишете что-то очень интенсивное в памяти, вам обычно не нужно отменять его (это одна из причин, по которой игры еще не часто пишутся в .Net - они нуждаются в полном контроле)

В .Net вы можете использовать GC.Collect() , чтобы заставить его немедленно сделать это, но это почти всегда плохая практика. Если .Net еще не очистил его, это означает, что сейчас не самое подходящее время для этого.

GC.Collect() выбирает объекты, которые .Net идентифицирует как выполненные. Если вы не избавились от объекта, который нуждается в нем, .Net может решить оставить этот объект. Это означает, что GC.Collect() эффективен только в том случае, если вы правильно реализуете свои одноразовые экземпляры.

GC.Collect() не является заменой для правильного использования IDisposable.

Таким образом, Dispose и память не связаны напрямую, но они и не должны быть связаны. Правильное размещение сделает ваши приложения .Net более эффективными и, следовательно, будет использовать меньше памяти.


99% из всех случаев в .Net лучшей практикой является следующая:

Правило 1: Если вы не имеете дела с чем-то неуправляемым или что реализует IDisposable , то не беспокойтесь о Dispose.

Правило 2: Если у вас есть локальная переменная, реализующая IDisposable, убедитесь, что вы избавились от нее в текущей области видимости:

//using is best practice
using( SqlConnection con = new SqlConnection("my con str" ) )
{
    //do stuff
} 

//this is what 'using' actually compiles to:
SqlConnection con = new SqlConnection("my con str" ) ;
try
{
    //do stuff
}
finally
{
    con.Dispose();
}

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

//rather basic example
public sealed MyClass :
   IDisposable
{   
    //this connection is disposable
    public SqlConnection MyConnection { get; set; }

    //make sure this gets rid of it too
    public Dispose() 
    {
        //if we still have a connection dispose it
        if( MyConnection != null )
            MyConnection.Dispose();

        //note that the connection might have already been disposed
        //always write disposals so that they can be called again
    }
}

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

Правило 4: Если класс использует неуправляемый ресурс, то реализуйте IDispose и добавьте завершитель.

.Net ничего не может сделать с неуправляемым ресурсом, поэтому сейчас мы говорим о памяти. Если вы не очистите его, то можете получить утечку памяти.

Метод Dispose должен работать как с управляемыми , так и с неуправляемыми ресурсами.

Завершитель является предохранителем-он гарантирует, что если кто-то другой создаст экземпляр вашего класса и не сможет его утилизировать, то неуправляемые ресурсы 'dangerous' все еще могут быть очищены с помощью файла .Net.

~MyClass()
{
    //calls a protected method 
    //the false tells this method
    //not to bother with managed
    //resources
    this.Dispose(false);
}

public void Dispose()
{
    //calls the same method
    //passed true to tell it to
    //clean up managed and unmanaged 
    this.Dispose(true);

    //as dispose has been correctly
    //called we don't need the 

    //'backup' finaliser
    GC.SuppressFinalize(this);
}

Наконец эта перегрузка Dispose которая принимает логический флаг:

protected virtual void Dispose(bool disposing)
{
    //check this hasn't been called already
    //remember that Dispose can be called again
    if (!disposed)
    {
        //this is passed true in the regular Dispose
        if (disposing)
        {
            // Dispose managed resources here.
        }

        //both regular Dispose and the finaliser
        //will hit this code
        // Dispose unmanaged resources here.
    }

    disposed = true;
}

Обратите внимание, что как только все это будет сделано, другой управляемый код, создающий экземпляр вашего класса, может просто рассматривать его как любой другой IDisposable (правила 2 и 3).


  Сведения об ответе

crush

21:30, 14th August, 2020

Уместно ли также упомянуть, что dispose не всегда относится к памяти? Я располагаю ресурсами таких ссылок на файлы чаще, чем на память. GC.Collect() непосредственно относится к сборщику мусора CLR и может или не может освободить память (в Диспетчере задач). Это, скорее всего, негативно повлияет на ваше приложение (например, производительность).

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


  Сведения об ответе

lats

05:10, 2nd August, 2020

Взгляните на эту статью

Реализация шаблона Dispose, IDisposable и / или финализатора не имеет абсолютно никакого отношения к тому, когда память восстанавливается; вместо этого она имеет все отношение к указанию GC, как восстановить эту память. Когда вы вызываете Dispose(), вы никоим образом не взаимодействуете с GC.

GC будет работать только тогда, когда он определит необходимость (называемую давлением памяти), а затем (и только тогда) он освободит память для неиспользуемых объектов и сократит объем памяти.

Вы можете позвонить GC.Collect(), но вам действительно не следует этого делать, если нет очень веской причины (которая почти всегда "Never"). Когда вы заставляете out-of-band цикл сбора данных, подобный этому, вы фактически заставляете GC выполнять больше работы и в конечном итоге можете повредить производительность ваших приложений. На протяжении цикла сбора данных GC ваше приложение фактически находится в замороженном состоянии state...the чем больше циклов GC выполняется, тем больше времени ваше приложение проводит в замороженном состоянии.

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

Вся предпосылка, лежащая в основе среды выполнения gargbage collected, заключается в том, что вам не нужно беспокоиться (так же сильно) о том, когда среда выполнения выделяет/освобождает фактическую память; вам нужно только беспокоиться о том, чтобы убедиться, что ваш объект знает, как убирать за собой, когда его спрашивают.


  Сведения об ответе

screen

08:38, 29th August, 2020

public class MyClass : IDisposable
{
    public void Dispose()
    {
       // cleanup here
    }
}

тогда вы можете сделать что-то вроде этого

MyClass todispose = new MyClass();
todispose.Dispose(); // instance is disposed right here

или

using (MyClass instance = new MyClass())
{

}
// instance will be disposed right here as it goes out of scope


  Сведения об ответе

VCe znayu

10:16, 13th August, 2020

Полное объяснение Джо Даффи на тему " утилизация, доработка и управление ресурсами ":

Ранее в рамках .NET-х годов время жизни, финализаторы были последовательно упоминается как деструкторы по C# программисты. По мере того как мы становимся умнее над время, мы пытаемся прийти к соглашению с тем, что метод Dispose действительно более эквивалентно a C++ деструктор (детерминированный), в то время как финализатор - это нечто совершенно другое отдельный (недетерминированный) . Факт что C# позаимствовал деструктор C++ синтаксис (т. е. ~T()) наверняка имел по крайней мере немного связано с развитием это неправильное название.


  Сведения об ответе

appple

12:40, 8th August, 2020

Я написал краткое описание деструкторов и Dispose и сборки мусора на http://codingcraftsman.wordpress.com/2012/04/25/to-dispose-or-not-to-dispose/

Чтобы ответить на первоначальный вопрос:

  1. Не пытайтесь управлять своей памятью
  2. Dispose-это не управление памятью, а управление неуправляемыми ресурсами
  3. Завершители являются врожденной частью шаблона Dispose и фактически замедляют высвобождение памяти управляемых объектов (поскольку они должны идти в очередь завершения, если уже не Dispose d)
  4. GC.Collect плохо, так как это заставляет некоторые недолговечные объекты казаться необходимыми для более длительного времени и поэтому замедляет их сбор.

Однако GC.Collect может быть полезен, если у вас есть критический для производительности раздел кода и вы хотите уменьшить вероятность замедления сборки мусора. Ты уже называл это раньше.

Кроме того, есть аргумент в пользу этой модели:

var myBigObject = new MyBigObject(1);
// something happens
myBigObject = new MyBigObject(2);
// at the above line, there are temporarily two big objects in memory and neither can be collected

против

myBigObject = null; // so it could now be collected
myBigObject = new MyBigObject(2);

Но главный ответ заключается в том, что сбор мусора просто работает, если вы не возитесь с ним!


  Сведения об ответе

padenie

17:24, 2nd August, 2020

Вы не можете действительно заставить GC очистить объект, когда вы хотите, хотя есть способы заставить его работать, ничто не говорит, что это очистить весь объект, который вы want/expect. лучше всего вызвать dispose в try catch ex finally dispose end try (VB.NET rulz) способ. Но Dispose предназначен для очистки системных ресурсов (памяти, дескрипторов, соединений с БД и т. д.). выделяется объектом детерминированным образом. Dispose не очищает (и не может) память, используемую самим объектом, только GC может это сделать.


  Сведения об ответе

pumpa

08:25, 15th August, 2020

В этой статье есть довольно простое пошаговое руководство. Однако необходимость вызывать GC вместо того, чтобы позволить ему идти своим естественным путем, как правило, является признаком плохого проектирования/управления памятью, особенно если не используются никакие ограниченные ресурсы (соединения, дескрипторы, все остальное, что обычно приводит к реализации IDisposable).

Чем это вызвано вам нужно сделать для этого?


  Сведения об ответе

lool

02:52, 13th August, 2020

Извините, но выбранный здесь ответ неверен. Как несколько человек впоследствии заявили, Dispose и реализация IDisposable не имеет ничего общего с освобождением памяти, связанной с классом .NET. Он в основном и традиционно используется для освобождения неуправляемых ресурсов, таких как дескрипторы файлов и т. д.

Хотя ваше приложение может вызвать GC.Collect(), чтобы попытаться принудительно собрать коллекцию сборщиком мусора, это действительно окажет влияние только на те элементы, которые находятся на правильном уровне генерации в очереди freachable. Таким образом, вполне возможно, что если вы очистили все ссылки на объект, то все еще может быть пара вызовов GC.Collect(), прежде чем фактическая память будет освобождена.

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

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


  Сведения об ответе

lool

06:27, 4th August, 2020

@Keith,

Я согласен со всеми вашими правилами, за исключением #4. добавление финализатора должно быть сделано только при очень специфических обстоятельствах. Если класс использует неуправляемые ресурсы, они должны быть очищены в вашей функции Dispose(bool). Эта же функция должна очищать управляемые ресурсы только в том случае, если bool имеет значение true. Добавление финализатора увеличивает сложность использования объекта, так как каждый раз при создании нового экземпляра он также должен быть помещен в очередь завершения, которая проверяется каждый раз, когда GC выполняет цикл сбора данных. Фактически это означает, что ваш объект переживает один цикл/поколение дольше, чем это должно быть, чтобы можно было запустить финализатор. Финализатор не следует рассматривать как "safety net".

GC будет выполнять цикл сбора только тогда, когда он определит, что в куче Gen0 недостаточно доступной памяти для выполнения следующего выделения, если только вы не сделаете это с помощью вызова GC.Collect() для принудительного сбора out-of-band.

Суть в том, что, несмотря ни на что, GC знает только, как освободить ресурсы, вызвав метод Dispose (и, возможно, финализатор, если он реализован). Это зависит от этого метода, чтобы "do the right thing" и очистить любые неуправляемые ресурсы, используемые и поручить любые другие управляемые ресурсы, чтобы вызвать их Dispose метод. Он очень эффективен в том, что он делает, и может самооптимизировать в значительной степени, если ему не помогают циклы сбора out-of-band. Тем не менее, за исключением явного вызова GC.Collect, вы не можете контролировать, когда и в каком порядке будут удалены объекты и освобождена память.


  Сведения об ответе

VERSUION

01:26, 16th August, 2020

Вы можете иметь детерминированное уничтожение объекта в c++

Вы никогда не хотите вызывать GC.Collect, это мешает самонастройке сборщика мусора, чтобы обнаружить давление памяти и в некоторых случаях не делать ничего, кроме увеличения текущего поколения каждого объекта в куче.

Для тех, кто публикует ответы IDisposable. Вызов метода Dispose не приводит к уничтожению объекта, как это описано в методе asker.


  Сведения об ответе

padenie

07:28, 29th August, 2020

Если MyClass реализует IDisposable, вы можете сделать именно это.

MyClass.Dispose();

Лучшая практика в C#-это:

using( MyClass x = new MyClass() ) {
    //do stuff
}

Как это оборачивает избавление в попытке-наконец-то и гарантирует, что его никогда не пропустят.


  Сведения об ответе

baggs

05:17, 7th August, 2020

Если вы не хотите (или не можете) реализовать IDisposable в своем классе, вы можете принудительно собрать мусор таким образом (но это медленно) -

GC.Collect();


  Сведения об ответе

SKY

22:30, 28th August, 2020

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


  Сведения об ответе

SEEYOU

21:52, 16th August, 2020

@Curt Хагенлохер - это задом наперед. Я понятия не имею, почему так много людей проголосовали за это, когда это неправильно.

IDisposable - для управляемых ресурсов.

Финализаторы предназначены для неуправляемых ресурсов.

Пока вы используете только управляемые ресурсы, и @Jon Limjap, и я полностью правы.

Для классов, которые используют неуправляемые ресурсы (и имейте в виду, что подавляющее большинство классов .Net этого не делают), ответ Патрика является исчерпывающим и наилучшим.

Избегайте использования GC.Collect - это медленный способ работы с управляемыми ресурсами и ничего не делает с неуправляемыми, если вы правильно построили свой ~Finalizers.


Я удалил комментарий модератора из исходного вопроса в соответствии с https://stackoverflow.com/questions/14593/etiquette-for-modifying-posts


  Сведения об ответе

baggs

15:12, 11th August, 2020

@Keith:

IDisposable - для управляемых ресурсов.

Финализаторы предназначены для неуправляемых ресурсов.

Извините, но это просто неправильно. Обычно финализатор вообще ничего не делает. Однако, если шаблон dispose был правильно реализован, финализатор пытается вызвать Dispose .

Dispose имеет два рабочих места:

  • Свободные неуправляемые ресурсы, а также
  • свободные вложенные управляемые ресурсы.

И здесь ваше утверждение вступает в игру, потому что верно, что при завершении объект никогда не должен пытаться освободить вложенные управляемые ресурсы, поскольку они, возможно, уже были освобождены. Однако он все равно должен освободить неуправляемые ресурсы.

Тем не менее, у завершителей нет другой задачи, кроме вызова Dispose и указания ему не трогать управляемые объекты. Dispose, вызванный вручную (или через Using ), освобождает все неуправляемые ресурсы и передает сообщение Dispose вложенным объектам (и методам базового класса), но это никогда не освободит никакой (управляемой) памяти.


  Сведения об ответе

piter

00:22, 8th August, 2020

Конрад Рудольф-ага, обычно финализатор вообще ничего не делает. Вы не должны реализовывать его, если не имеете дело с неуправляемыми ресурсами.

Затем, когда вы его реализуете, вы используете шаблон dispose корпорации Майкрософт (как уже описано)

  • public Dispose() вызовы protected Dispose(true) -работа как с управляемыми, так и с неуправляемыми ресурсами. Вызов Dispose() должен подавлять завершение процесса.

  • ~Finalize вызывает protected Dispose(false) -работает только с неуправляемыми ресурсами. Это предотвращает утечку неуправляемой памяти, если не удается вызвать public Dispose()

~Finalize работает медленно, и его не следует использовать, если у вас нет неуправляемых ресурсов для работы.

Управляемые ресурсы не могут пропускать память, они могут только тратить ресурсы для текущего приложения и замедлять его сборку мусора. Неуправляемые ресурсы могут протекать, и ~Finalize -это наилучшая практика, чтобы гарантировать, что они этого не делают.

В любом случае using -это наилучшая практика.


  Сведения об ответе

FAriza

19:31, 24th August, 2020

В ответе на первоначальный вопрос, с информацией, предоставленной до сих пор оригинальным плакатом, 100% уверен, что он не знает достаточно о программировании в .NET, чтобы даже получить ответ: используйте GC.Collect(). Я бы сказал, что это 99.99% вероятно, что ему действительно не нужно использовать GC.Collect() вообще, как указывало большинство плакатов.

Правильный ответ сводится к следующему: "пусть GC делает свою работу. Период. У тебя есть и другие причины для беспокойства. Но вы, возможно, захотите рассмотреть, следует ли и когда вы должны избавиться или очистить определенные объекты, и нужно ли вам реализовать IDisposable и, возможно, завершить работу в своем классе.'

Относительно должности Кита и его правления #4:

Некоторые плакаты путают Правило 3 и Правило 4. Правило 4 кита абсолютно верно, однозначно. Это единственное правило из четырех, которое вообще не нуждается в редактировании. Я бы немного перефразировал некоторые из его других правил, чтобы сделать их более ясными, но они по существу правильны, если вы их правильно проанализируете и фактически прочитаете весь пост, чтобы увидеть, как он их расширяет.

  1. Если ваш класс не использует неуправляемый ресурс AND, он также никогда не создает экземпляр другого объекта класса, который сам использует, непосредственно или в конечном счете, неуправляемый объект (т. е. класс, реализующий IDisposable), то вашему классу не нужно будет ни реализовывать IDisposable, ни даже вызывать .dispose на что-либо. (В таком случае глупо думать, что вы на самом деле NEED, чтобы немедленно освободить память с принудительным GC, так или иначе.)

  2. Если ваш класс использует неуправляемый ресурс, OR создает экземпляр другого объекта, который сам реализует IDisposable, то ваш класс должен либо:

    а) немедленно утилизируйте / освободите их в локальном контексте, в котором они были созданы, OR...

    б) реализовать IDisposable в шаблоне, рекомендованном в посте кита, или в нескольких тысячах мест в интернете, или буквально в 300 книгах к настоящему времени.

    b.1) кроме того, если (b), и это неуправляемый ресурс, который был открыт, и IDisposable, и Finalize всегда должны быть реализованы, согласно правилу кита #4.
    В этом контексте Finalize абсолютно IS защитная сетка в одном смысле: если кто-то создает экземпляр вашего объекта IDisposable, который использует неуправляемый ресурс, и они не могут вызвать dispose, то Finalize-это последний шанс для объекта YOUR закрыть неуправляемый ресурс должным образом.
    (Finalize должен сделать это, вызвав Dispose таким образом, чтобы метод Dispose пропускал освобождение чего-либо BUT неуправляемого ресурса. Кроме того, если метод Dispose вашего объекта IS правильно вызван любым экземпляром вашего объекта, то он BOTH передает вызов Dispose всем объектам IDisposable, которые он создал, AND освобождает неуправляемые ресурсы должным образом, заканчивая вызовом подавления Finalize на вашем объекте, что означает, что влияние использования Finalize уменьшается, если ваш объект правильно расположен вызывающим. Все эти пункты включены в сообщение кита, BTW.)

    b.2) IF ваш класс реализует только IDisposable, потому что он должен по существу передать Dispose объекту IDisposable, который он создал, а затем не реализовывать метод Finalize в вашем классе в этом случае. Finalize предназначен для обработки случая, когда оба Dispose никогда не вызывались любым экземпляром вашего объекта, AND был использован неуправляемый ресурс, который все еще не выпущен.

Короче говоря, что касается поста кита, то он совершенно прав, и этот пост, на мой взгляд, является самым правильным и полным ответом. Он может использовать некоторые краткие высказывания, которые некоторые находят 'wrong' или возражают против этого, но его полный пост расширяет использование Finalize полностью, и он абсолютно прав. Обязательно прочитайте его пост полностью, прежде чем перейти к одному из правил или предварительных утверждений в его посте.


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться