Я не являюсь поклонником шаблона кода: повторное использование копий-пасты потенциально подвержено ошибкам. Даже если вы используете фрагменты кода или смарт-шаблоны, нет гарантии, что другой разработчик сделал это, и это означает, что нет никакой гарантии, что они сделали это правильно. И, если вам нужно увидеть код, вы должны понять его и/или сохранить его.Является ли это законной альтернативой «традиционному» шаблону размещения для иерархии классов?
Что я хочу знать из сообщества: является ли моя реализация IDispose для иерархии классов законной альтернативой "traditional" dispose pattern? По законным, я имею в виду правильные, разумно хорошо исполняемые, надежные и поддерживаемые.
Я согласен с тем, что эта альтернатива выглядит неправильно, но если да, то я бы хотел знать, почему.
Эта реализация предполагает, что вы имеете полный контроль над иерархией классов; если вы этого не сделаете, вам, вероятно, придется вернуться к шаблону. Звонки на Добавить *() обычно будет выполнен в конструкторе.
public abstract class DisposableObject : IDisposable
{
protected DisposableObject()
{}
protected DisposableObject(Action managedDisposer)
{
AddDisposers(managedDisposer, null);
}
protected DisposableObject(Action managedDisposer, Action unmanagedDisposer)
{
AddDisposers(managedDisposer, unmanagedDisposer);
}
public bool IsDisposed
{
get { return disposeIndex == -1; }
}
public void CheckDisposed()
{
if (IsDisposed)
throw new ObjectDisposedException("This instance is disposed.");
}
protected void AddDisposers(Action managedDisposer, Action unmanagedDisposer)
{
managedDisposers.Add(managedDisposer);
unmanagedDisposers.Add(unmanagedDisposer);
disposeIndex++;
}
protected void AddManagedDisposer(Action managedDisposer)
{
AddDisposers(managedDisposer, null);
}
protected void AddUnmanagedDisposer(Action unmanagedDisposer)
{
AddDisposers(null, unmanagedDisposer);
}
public void Dispose()
{
if (disposeIndex != -1)
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
~DisposableObject()
{
if (disposeIndex != -1)
Dispose(false);
}
private void Dispose(bool disposing)
{
for (; disposeIndex != -1; --disposeIndex)
{
if (disposing)
if (managedDisposers[disposeIndex] != null)
managedDisposers[disposeIndex]();
if (unmanagedDisposers[disposeIndex] != null)
unmanagedDisposers[disposeIndex]();
}
}
private readonly IList<Action> managedDisposers = new List<Action>();
private readonly IList<Action> unmanagedDisposers = new List<Action>();
private int disposeIndex = -1;
}
Это «полное» осуществление в том смысле, я обеспечиваю поддержку завершения (зная, что большинство реализаций не требуется финализации), проверяя, расположен ли объект и т.д. Реальная реализация может удалить финализации , например, или создать подкласс DisposableObject, который включает финализатор. В принципе, я бросил все, что мог думать только по этому вопросу.
Возможно, есть некоторые краевые случаи и эзотерические ситуации, которые я пропустил, поэтому я приглашаю кого-либо выкалывать дыры в этом подходе или беречь его с исправлениями.
Другие альтернативы может быть использование одной очереди <Disposer> в отвечающих за удаление DisposableObject вместо двух списков; в этом случае, когда вызывающие вызовы вызываются, они удаляются из списка. Есть и другие незначительные вариации, о которых я могу думать, но они имеют одинаковый общий результат: никакого шаблона кода.
Это все еще страдает от того факта, что разработчики должны помнить о вызове метода Add() для агрегированных типов. Лично я не думаю, что это может принести пользу по обычной схеме. –
Не делайте этого. Используйте Pattern Dispose как написано. Опытные разработчики сразу поймут код, вы покроете все базы, такие инструменты, как FxCop, помогут проверить его, вы можете написать фрагменты, чтобы точно реализовать его, и вы будете придерживаться стандартов Microsoft. http://www.bluebytesoftware.com/blog/PermaLink.aspx?guid=88e62cdf-5919-4ac7-bc33-20c06ae539ae – TrueWill
Как в стороне, если вы хотите, это DisposableCollection, вы должны быть в состоянии найти количество реализаций этого. –
TrueWill