2015-03-12 1 views
0

Правильно ли, что в C# Destructor (Finalizer) вы не можете получить доступ к управляемым членам вашего класса? Если это так, то почему? Какие еще ограничения для финализатора C# вы знаете?Ограничения деструктора - доступ к управляемому члену из destructor

Пример:

class MyClass 
{ 
    private FileStream _fs; 
    private IntPtr _handle; 

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

    ~MyClass() 
    { 
     Dispose(false); 
    } 

    private void Dispose(bool isDisposing) 
    { 
     if (isDisposing) 
     { 
      _fs.Dispose(); // Won't be accessed from destructor 
     } 

     //some way to release '_handle' - this happans anyway (Called by Dispose or by Destructor) 
    } 
} 
+0

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

+0

На всякий случай, когда вы не знали, финализаторы считаются плохой практикой в ​​C# (наряду со многими другими операциями управления памятью, которые разрушают встроенную сборку мусора). См. Шаблон IDisposable в качестве альтернативы (https://msdn.microsoft.com/en-us/library/system.idisposable%28v=vs.110%29.aspx) – Kaido

ответ

1

Да, вы не должны получить доступ к другим классам управляемых из финализаторе, или из Dispose, когда этот метод вызывается финализации. К моменту завершения финализатора объекта состояние любого управляемого объекта, который он когда-то ссылался, является неопределенным. Они все еще могут существовать, могут сами ожидать завершения или, возможно, уже собраны мусор. Кроме того, финализаторы запускаются по другой теме.

+0

Спасибо. вот что имеет смысл для меня. – AlonP

1

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

из MSDN

Использования деструкторов для освобождения ресурсов: В общем, C# не требует столько управления памятью, как это необходимо при разработке с языком, который не направлен средой выполнения со сборкой мусора , Это связано с тем, что сборщик мусора .NET Framework неявно управляет распределением и выпуском памяти для ваших объектов. Однако, когда ваше приложение инкапсулирует неуправляемые ресурсы, такие как окна, файлы и сетевые подключения, вы должны использовать деструкторы для освобождения этих ресурсов. Когда объект имеет право на уничтожение, сборщик мусора запускает метод Finalize объекта.

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

https://msdn.microsoft.com/en-us/library/66x5fx1b.aspx

1

Это деталь реализации .NET 1.x, которая была невероятно трудно избавиться. Часть проблемы должна заключаться в том, что большинство книг о .NET были написаны до 2005 года, все они имеют главу о финализаторах, и все они ошибаются.

Грубо, если вы думаете, что вам нужен финализатор, тогда вы ошибаетесь 99,9% времени. Этот завершаемый ресурс должен быть завернут в свой класс и , что класс должен иметь финализатор. Если вы думаете, вам нужно реализовать одноразовый паттерн, тогда вы ошибаетесь ~ 95% времени. Определенно неправильно здесь. Но иногда у вас нет выбора, если ваш базовый класс уже допустил ошибку при его реализации. У некоторых классов .NET Framework есть эта ошибка, проблема, которую Microsoft не может исправить.

что класс с финализатором в предыдущей главе не один вы должны реализовать себя.Уже было написано: .NET 2.0 приобрел классы SafeHandle. Вам, в лучшем случае, может потребоваться вывести свой собственный класс, если метод Release() не тот, который уже предоставлен в рамках. SafeBuffer полезен для ресурсов, основанных на указателях.

Большая разница заключается в том, что эти классы довольно особенные, у них есть критические финализаторы. Это дорогое слово, которое означает, что они гарантированно будут работать, даже если поток финализатора бомбит на необработанном исключении. На самом деле это не важно в большинстве приложений LOB, если они спускаются в огонь, тогда очистка ОС обычно достаточно хороша. Но важно, когда .NET-код работает на хосте, который имеет длительную гарантию безотказной работы. SQL Server - хороший пример, нужно перезагрузить его, потому что слишком много кода SQL/CLR, подвергшегося бомбардировке и пропущенным ручкам, плохо для бизнеса.

+0

Почему я ошибаюсь в этом случае? У меня есть член (filestream), который является одноразовым, поэтому я должен заверить, что его распоряжение вызывается. – AlonP

+0

Итак, просто вызовите метод Dispose() в методе Dispose(). Это все, что вам нужно, ничего общего с финализацией. –

Смежные вопросы