- IDisposableを実装したクラスを、複数クラス間で共有して利用する。
- QueryInterfaceメソッドで、参照のコピーを取得。
- Disposeを行うことで、参照カウントが減算される。
巨大な画像リソースを使いまわしたいケースなどを想定。
生成者と利用者が分散、かつ利用者が複数クラスにまたがる場合を想定。
重たいリソースをコピーせずに共有するため。
厳密なリソース管理をする必要がないならば、WeakReferenceを利用するのも手。
利用中は強参照、利用していなければ弱参照として扱うことができ、
参照頻度が高い間は使いまわすことができ、参照頻度が低い場合はGCによって回収される。
※管理がGC頼みになってしまうので、消費リソース量が多い場合は取るべきではないと考えている。
そもそも弱参照は使い所を選ばないと、何かあった時のメンテナンスが大変・・・
// Bitmapを共有 Shared<Bitmap> tmp; Shared<Bitmap> bmp = new Shared<Bitmap>(new Bitmap(100, 100)); // bmpインスタンスをコピー tmp = bmp.QueryInterface(); // 参照カウント+1 // 〜bmpインスタンスを利用〜 bmp.Dispose(); // ここではBitmapはまだDisposeされない // 〜tmpインスタンスを利用〜 tmp.Dispose(); // ここでBitmapがDisposeされる
/// <summary>共有オブジェクトクラス</summary> /// <typeparam name="TDisposable">共有対象クラス</typeparam> public class Shared<TDisposable> : IDisposable where TDisposable : class, IDisposable { private TDisposable _target; /// <summary>共有対象オブジェクト</summary> public TDisposable Target { get { return _target; } } /// <summary>参照カウンタクラス</summary> private SharedCounter _counter = new SharedCounter(); /// <summary>開放済みかどうか</summary> public bool IsDisposed { get { return _counter.IsDisposed; } } /// <summary>コンストラクタ</summary> /// <param name="target">共有対象オブジェクト</param> public Shared(TDisposable target) { _target = target; _counter.Addref(); } /// <summary>コンストラクタ(参照コピー用)</summary> /// <param name="target">共有対象オブジェクト</param> /// <param name="counter">参照カウンタ</param> private Shared(TDisposable target, SharedCounter counter) { _target = target; _counter = counter; _counter.Addref(); } /// <summary>新たな参照を取得する。</summary> /// <returns></returns> public Shared<TDisposable> QueryInterface() { return new Shared<TDisposable>(_target, _counter); } #region IDisposable メンバー /// <summary>参照カウントを減算し、参照がなくなればDisposeする。</summary> public void Dispose() { // 開放済みであれば何もしない if (_counter.IsDisposed) return; // 参照を削除する。 _counter.Release(); if (!_counter.IsFree) return; if (_target != null) { _target.Dispose(); _target = null; _counter.IsDisposed = true; } } #endregion #region 共有カウンタ /// <summary>共有カウンタクラス</summary> private class SharedCounter { /// <summary>カウンタ</summary> private int _count; /// <summary>参照がないかどうか</summary> public bool IsFree { get { return _count <= 0; } } /// <summary>開放済みかどうか</summary> public bool IsDisposed { get; set; } /// <summary>参照の追加</summary> public void Addref() { _count++; } /// <summary>参照の削除</summary> public void Release() { _count--; } } #endregion }
コメントをかく