Я читал об удалении объектов / интерфейса IDisposable и деструкторов в C#, но мне кажется, что они делают то же самое?
Какая разница между двумя? Почему я должен использовать одно вместо другого? Фактически, в этом примере (ссылка ниже) этот код использует как интерфейс IDisposable, так и деструктор:
http://msdn.microsoft.com/en-us/library/system.idisposable.aspx
В комментарии говорится, что деструктор - это если код завершения не используется, но как мне решить, когда использовать один вместо другого?
Возможный дубликат В чем разница между использованием IDisposable и деструктора в C#?





Я написал довольно подробный пост, который должен помочь объяснить о финализаторах, IDisposable и о том, когда следует использовать тот или иной: http://gregbee.ch/blog/implementing-and-using-the-idisposable-interface
Вероятно, самая важная часть цитируется ниже:
When you are using unmanaged resources such as handles and database connections, you should ensure that they are held for the minimum amount of time, using the principle of acquire late and release early. In C++ releasing the resources is typically done in the destructor, which is deterministically run at the point where the object is deleted. The .NET runtime, however, uses a garbage collector (GC) to clean up and reclaim the memory used by objects that are no longer reachable; as this runs on a periodic basis it means that the point at which your object is cleaned up is nondeterministic. The consequence of this is that destructors do not exist for managed objects as there is no deterministic place to run them.
Instead of destructors, C# has finalizers which are implemented by overriding the Finalize method defined on the base Object class (though C# somewhat confusingly uses the C++ destructor syntax ~Object for this). If an object overrides the Finalize method then rather than being collected by the GC when it is out of scope, the GC places it on a finalizer queue. In the next GC cycle all finalizers on the queue are run (on a single thread in the current implementation) and the memory from the finalized objects reclaimed. It's fairly obvious from this why you don't want to do clean up in a finalizer: it takes two GC cycles to collect the object instead of one and there is a single thread where all finalizers are run while every other thread is suspended, so it's going to hurt performance.
So if you don't have destructors, and you don't want to leave the cleanup to the finalizer, then the only option is to manually, deterministically, clean up the object. Enter the IDisposable interface which provides a standard for supporting this functionality and defines a single method, Dispose, where you put in the cleanup logic for the object. When used within a finally block, this interface provides equivalent functionality to destructors. The reason for finally blocks in code is primarily to support the IDisposable interface; this is why C++ uses simply try/except as there is no need for a finally block with destructors.
Ссылка мертвая видимо, у вас есть еще одна ссылка на пост?
По крайней мере, сейчас вы все еще можете получить его из кеша Google: goo.gl/1dTmL
Небольшая нить: синтаксический элемент в C#, помеченный тильдой, за которой следует имя класса, правильно называется деструктором в C#, потому что это термин, используемый людьми, написавшими спецификацию C#. Поведение деструктора C# не имеет никакого отношения к поведению деструктора C++, и название довольно глупое, поскольку деструктор C# на самом деле не уничтожает объект, а скорее дает объекту которые в противном случае были бы уничтожены отсрочку, чтобы он мог привести свои дела в порядок.
@supercat - в прошлом Microsoft фактически использовала оба слова для описания этой функциональности в контексте C#. Хотя в официальной документации обычно используется слово «деструктор», я предпочитаю использовать термин «финализатор», чтобы избежать путаницы или наложения неправильной семантики. Многие из разработчиков .NET framework согласны с этой позицией: bluebytesoftware.com/blog/…
@GregBeech: термин «финализатор» относится к переопределению Object.Finalize, независимо от того, как такое переопределение производится. Термин «деструктор» относится к синтаксическому элементу, который предписывает компилятору C# создать финализатор, который вызывает указанный код, а также финализатор базового класса.
@supercat - Как я уже сказал, да, технически это правда, но я все еще не люблю использовать этот термин даже в контексте C#. Прочтите связанный ресурс, и вы увидите комментарий: "C#, возможно, подчеркивает неправильный аспект времени жизни объекта (вместо времени жизни ресурса), дав специальному имени C++ неправильное значение. Но обратите внимание, что когда вы видите слово деструктор или ~ T () в любом обсуждении Dispose () или времени жизни объекта , обратите внимание именно на то, что задумал автор. Я предпочитаю использовать «finalizer» и «dispose», чтобы избежать путаницы, вызванной языком ». - Брайан Грюнкемейер
@GregBeech: C# определенно подчеркивает неправильный аспект времени жизни объекта и делает это способом, который претендует на переносимость, но на самом деле это не так. Кроме того, с точки зрения CLR, сборщик мусора запускает финализаторы и не имеет представления о том, что такое деструктор. Я думаю, что мы в этом насильственном соглашении. Я хотел сказать, что при обсуждении особенностей того, как C# обертывает финализаторы, необходимо использовать термин «деструктор», независимо от того, насколько неудачным может быть такой выбор терминологии.
Финализатор дает вам возможность для удаления неуправляемых ресурсов в случае, если пользователь вашего объекта забыл вызвать IDisposable.Dispose.
Если ваш объект реализует IDisposable, пользователь вашего объекта должен вызывает .Dispose. Вы не можете использовать имеют для наведения порядка в пользователе; но это приятно.
Мой самый популярный ответ на Stackoverflow с самого начала объясняет вам, почему у вас есть IDisposable, что он должен делать, что может делать ваш финализатор, чего он не должен делать.
This answer melts faces
был использован для его описания: P
ТЫ МОЖЕШЬ ЛУЧШЕ! (извините, пришлось. также, не смог устоять перед голосом за этот ответ, хотя финальный «вот как должен выглядеть базовый класс» в конце, вероятно, поможет другим). Кстати, это ответ сообщества вики. , значит, тебе за это не начисляются баллы, верно?
@JoeBrockhaus Думаю, нет. Вот что произойдет, если вы продолжите редактировать ответ, чтобы улучшить его.
Наличие деструктора (~ Object ()) в управляемом языке программирования - самая глупая идея. Для неуправляемых языков, таких как C, C++, вполне имеет смысл иметь деструкторы, поскольку они используют идиому RAII, но для управляемых, таких как Java, C#, это просто абсурд.
Джошуа Блох, бывший руководитель проекта Java Collection Framework, отмечал, что идея метода finalize () (который эквивалентен деструктору, подобному C++ в C#) в Java была самой большой ошибкой из когда-либо сделанных. Как и в C#, функция finallize () в Java дает накладные расходы на «новый», поскольку он должен быть добавлен в очередь финализатора во время выделения. Более того, сборщик мусора должен выскакивать и запускать finallize () в очереди, поэтому в два раза больше накладных расходов во время gc.
В C# было много расширенных функций, таких как using (IDisposable) {}, которые не только позволяют ограничить переменную IDisposable областью блока using, но также гарантируют ее очистку. У меня вопрос, почему C# пошел по тому же пути, что и Java, что привело к большой ошибке. Возможно, если бы разработка dotnet началась примерно после 2003–2005 гг., Когда многие архитекторы Java обнаружили ошибку finallize (), то ошибку можно было бы предотвратить.
Многие хорошие идеи одного языка часто переносятся на другой язык, например, «IDisposable / using combo» в C#, который был перенесен в Java 1.7 в его операторе «try (object-to-dispose) {}». Но очень плохо, что архитекторы языка не могут обнаружить плохую идею, замаскированную под хорошую, во время ее передачи от одного к другому.
Я советую никогда не использовать ~ Destructor () и придерживаться IDisposable / using combo, если вам нужно вручную очистить неуправляемый ресурс, такой как соединения с базой данных.
Привет, Дэвид, IDisposable был необходим для управления выделенной памятью, не выделенной фреймворком, как окна, используемые в WinForms. Это необходимо до завершения langage (без внешних зависимостей).
Я согласен в теоретическом смысле; лучше бы они не понадобились. Однако, поскольку на практике вы не можете рассчитывать на то, что вызывающий абонент вызовет dispose, вам иногда понадобится дополнительная лазейка для обеспечения завершения. Одноразовый шаблон (goo.gl/YoGsr) специально предназначен для того, чтобы вызвать finalize только в том случае, если клиент пренебрегает вызовом dispose. Придерживаясь "потому что теории!" Аргумент приводит нас к обязательным операторам using для чего-либо IDisposable, что не является разумным решением - даже хуже, чем проблемы с отмеченными / непроверенными исключениями в java.
Привет, @dcw, я признаю, что наличие как Dispose (), так и finallize () делает его надежным решением для управления ресурсом, который необходимо очистить перед сборкой мусора. Но я почти не вижу случая, когда finallize () действительно приходит на помощь и устраняет беспорядок, такой как пауза сборки мусора или ошибка пустого пула БД из-за того, что не вызывается Dispose (). Я видел это как в Windows 2003 / asp.net, так и в IBM AIX / JDK1.5 / spring. В основном в этом случае webapp приостанавливается на неопределенный срок, и я просто считаю, что поток коллекции gabage мертв, поэтому я просто перезапускаю конкретный веб-контейнер COM + или Java.
См. этот вопрос.