Я действительно ищу некоторую мудрость лучшей практики. Таким образом, вот вопросы, я добавлю больше, если люди оставят комментарии. Не стесняйтесь отвечать на некоторых или все эти вопросы.
Когда я ДОЛЖЕН использовать IDisposable? Только, когда у меня есть неуправляемые ресурсы?
Что изменения расположить шаблона там и почему они варьируются?
Что такое общие неуправляемые ресурсы, о которых я должен знать?
Это когда-нибудь неправильно или вводящий в заблуждение для реализации IDisposable?
Должен Расположить вызовы когда-нибудь быть объединенным в цепочку вместе, или мы должны полагаться на использование операторов? Например:
public Dispose(bool disposing)
{
...
this.SomeDependency.Dispose;
}
Вау. Здесь много вопросов!
Когда СЛЕДУЕТ использовать IDisposable? Только когда у меня есть неуправляемые ресурсы?
IDisposable
обычно используется для очистки ресурсов, но это не обязательно все, для чего он подходит. Это общий шаблон для уведомления потребляемого объекта о том, что с ним покончено. Одним из примеров является таймер:
using(var timer = new MyTimer())
{
//do some stuff
}
В этом случае вызов Dispose
не обязательно освобождает какие-либо ресурсы, это просто удобный и последовательный (два ключа для шаблона!) Способ сказать таймеру «ОК» , Я с тобой покончил », и таймер может остановить отсчет времени и, возможно, записать время где-нибудь.
Еще одно хорошее практическое правило: если вам нужен финализатор по какой-либо причине, вы должны также предоставить IDisposable
доступ к той же подпрограмме, чтобы потребляющий класс мог вместо этого завершить класс раньше. ожидания на GC.
Какие существуют варианты шаблона удаления и почему они различаются?
Есть только один реальный «конкретный» тип реализации IDisposable
, о котором я знаю - шаблон Finalize / Dispose:
public class MyClass : IDisposable
{
void IDisposable.Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// Free other state (managed objects).
}
// Free your own state (unmanaged objects).
// Set large fields to null.
}
~MyClass()
{
Dispose(false);
}
}
Какие общие неуправляемые ресурсы мне следует знать?
Все, что реализует IDisposable
, особенно в библиотеках .NET, должно иметь дескрипторы для неуправляемых ресурсов и должно быть удалено. Обычно через них вы получаете доступ только к неуправляемым ресурсам. Если нет, то вы знаете - обычно строят драйвер или что-то в этом роде.
Реализовать IDisposable когда-либо неправильно или вводить в заблуждение?
Злоупотреблять им может быть бессмысленно, но не вредно.
Должны ли вызовы Dispose объединяться в цепочку
Класс должен удалять только те IDisposables, которые он создает внутри. Если у него есть одноразовые зависимости, которые были внедрены или находятся за пределами класса, вы никогда не должны избавляться от них.
Есть две основные вещи, которые я написал относительно IDisposable
, и я рекомендую вам прочитать хотя бы первую: How to Implement IDisposable and Finalizers - 3 Easy Rules (у меня также есть другие записи в блоге на эту тему) и IDisposable - What Your Mother Never Told You about Resource Deallocation.
Когда ДОЛЖЕН использоваться IDisposable? Только когда у меня есть неуправляемые ресурсы?
IDisposable
следует использовать для одной из трех вещей: освобождение неуправляемого ресурса, освобождение управляемых ресурсов и RAII. Я предпочитаю использовать разные паттерны для этих разных нужд.
Обратите внимание, что все остальные мои ответы (и ссылки) обсуждают IDisposable
в контексте освобождения ресурсов. Они не затрагивают RAII.
Какие существуют разновидности шаблона dispose и почему они различаются?
Шаблон Microsoft является наиболее известным. Он позволяет освобождать неуправляемые и управляемые ресурсы и допускает наследование. Я предпочитаю более простой шаблон, описанный в моем блоге (3 простых правила), которому Microsoft фактически следует с .NET 2.0.
О каких общих неуправляемых ресурсах я должен знать?
Я предпочитаю иметь один класс IDisposable
для каждого типа неуправляемых ресурсов (подобно SafeFileHandle
от Microsoft). Таким образом, каждый раз, когда вы добавляете тип неуправляемого ресурса в свою программу/библиотеку, вам придется обрабатывать его только один раз.
Тогда возникает вопрос: "Какие классы я должен утилизировать?", на который есть простой ответ: "все классы, реализующие IDisposable
."
Разве реализация IDisposable может быть неправильной или вводить в заблуждение?
Нет. Пустая реализация IDisposable
- это всегда вариант. Вы должны рассмотреть возможность добавления IDisposable
в интерфейсы или базовые классы, если вы думаете, что реализация может их использовать. Это вопрос проектирования, о котором я подробнее рассказываю в статье What Your Mother Never Told You.
Следует ли вообще связывать вызовы Dispose вместе или лучше полагаться на операторы using?
Обычно Dispose
вызывает Dispose
для всех объектов-членов, которыми он владеет. Подробнее см. в моем втором правиле в блоге.