私はボイラープレート コードのファンではありません。コピーして貼り付けて再利用すると、エラーが発生しやすくなります。コード スニペットやスマート テンプレートを使用したとしても、他の開発者が正しく行ったという保証はありません。そして、コードを見る必要がある場合は、それを理解したり、維持したりする必要があります。
コミュニティから知りたいのは、クラス階層のIDisposeの実装は、 「従来の」破棄パターンの正当な代替手段ですか? 正当とは、正しく、適度にパフォーマンスが高く、堅牢で、保守可能であることを意味します。
この代替案が明らかに間違っていても問題ありませんが、そうである場合は、その理由を知りたいです。
この実装は、クラス階層を完全に制御できることを前提としています。そうしないと、定型コードに頼らざるを得なくなるでしょう。Add*()の呼び出しは通常、コンストラクターで行われます。
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のサブクラス。基本的に、この質問のためだけに考えられるすべてを投入しました。
おそらく、私が見逃したエッジケースや難解な状況がいくつかあるので、このアプローチに穴を開けるか、修正して補強するために誰かを招待します.
他の方法として、DisposableObject で 2 つのリストの代わりに単一の Queue<Disposer> ディスポーザーを使用することもできます。この場合、ディスポーザーが呼び出されると、リストから削除されます。他にも考えられるわずかなバリエーションがありますが、一般的な結果は同じで、ボイラープレート コードはありません。