Это может быть безопасным, чтобы не вызывать Dispose
, но проблема в том, что, когда дело обстоит так.
Хорошие 95% IEnumerator<T>
реализаций имеют Dispose
это безопасно игнорировать, но 5% - это не только 5%, которые вызовут ошибку, но и 5%, которые вызовут неприятную ошибку.Более того, код, который проходит через IEnumerator<T>
, будет видеть 95% и 5% и не сможет динамически разделять их (возможно реализовать неуниверсальный IEnumerable
без реализации IDisposable
и насколько хорошо это оказалось, можно догадаться, когда MS решила заставить IEnumerator<T>
наследовать от IDisposable
!).
Из остальных, может быть, 3 или 4% времени это безопасно.Теперь.Вы не знаете, какие 3%, не взглянув на код, и даже тогда в контракте говорится, что вы должны вызывать его, поэтому разработчик может рассчитывать на то, что вы сделаете это, если выпустят новую версию там, где это важно.
В итоге всегда звоните Dispose()
.(Я могу придумать исключение, но, честно говоря, это слишком странно, чтобы даже вдаваться в подробности, и в этом случае все еще безопасно называть его, но не жизненно важно).
По вопросу реализации IDisposable
себя, избегайте шаблона в этом проклятом документе .
Я считаю этот паттерн анти-паттерном.Это хороший шаблон для реализации как IDisposable.Dispose
, так и финализатора в классе, который содержит как управляемые, так и неуправляемые ресурсы.Однако в первую очередь держать как управляемые IDisposable
, так и неуправляемые ресурсы - это плохая идея.
Вместо этого:
Если у вас есть неуправляемый ресурс, то не имеете никаких неуправляемых ресурсов, которые реализуютIDisposable
.Теперь пути к кодам Dispose(true)
и Dispose(false)
одинаковы, поэтому в действительности они могут стать:
public class HasUnmanaged : IDisposable
{
IntPtr unmanagedGoo;
private void CleanUp()
{
if(unmanagedGoo != IntPtr.Zero)
{
SomeReleasingMethod(unmanagedGoo);
unmanagedGoo = IntPtr.Zero;
}
}
public void Dispose()
{
CleanUp();
GC.SuppressFinalize(this);
}
~HasUnmanaged()
{
CleanUp();
}
}
Если у вас есть управляемые ресурсы, которые необходимо утилизировать, просто сделайте это:
public class HasUnmanaged : IDisposable
{
IDisposable managedGoo;
public void Dispose()
{
if(managedGoo != null)
managedGoo.Dispose();
}
}
Там нет никакого загадочного "избавления" от bool (как можно назвать Dispose
и взять false
за то, что называется disposing
?) Не беспокойтесь о финализаторах в 99,99% случаев, когда вы не будетеони нужны (вторая модель встречается чаще, чем первая).Все хорошо.
Действительно нужно что-то, что имеет как управляемый, так и неуправляемый ресурс?Нет, на самом деле вы не заключаете неуправляемый ресурс в собственный класс, который работает с ним как дескриптор, а затем этот дескриптор соответствует первому шаблону выше, а основной класс - второму.
Толькореализуйте шаблон CA10634, когда вы вынуждены, потому что вы унаследовали от класса, который сделал это.К счастью, большинство людей больше не создают такие новые.