を使用すると、List<WeakReference>
希望どおりに機能しません。私が欲しいのは、WeakReferencesが参照するオブジェクトがガベージコレクションされるたびに、リストから自動的に削除されることです。
ConditionalWeakTable<TKey,TValue>
そのキーと値は弱く参照されて収集可能ですが、それらを列挙することはできないので、私も満足しません!
を使用すると、List<WeakReference>
希望どおりに機能しません。私が欲しいのは、WeakReferencesが参照するオブジェクトがガベージコレクションされるたびに、リストから自動的に削除されることです。
ConditionalWeakTable<TKey,TValue>
そのキーと値は弱く参照されて収集可能ですが、それらを列挙することはできないので、私も満足しません!
の実装は可能であることに同意しますが、それは必ずしも簡単WeakList<T>
ではないと思います。ここで私の実装を使用することを歓迎します。クラスはに依存し、はに依存します。WeakCollection<T>
WeakReference<T>
SafeGCHandle
WeakList<T>
をラップするクラスを簡単に実装できますList<WeakReference>
。
ガベージコレクションされたオブジェクトを自動的に削除する方法はありません。これは、オブジェクトがいつ発生したかを検出できないためです。ただし、WeakReference.IsAlive
プロパティを確認することで、「デッド」(ガベージコレクション)オブジェクトに遭遇したときにそれらを削除できます。ただし、このアプローチは、クライアントの観点から混乱を招く可能性があるため、お勧めしません。代わりに、Purge
明示的に呼び出すデッドエントリを削除するメソッドを実装することをお勧めします。
実装例は次のとおりです。
public class WeakList<T> : IList<T>
{
private List<WeakReference<T>> _innerList = new List<WeakReference<T>>();
#region IList<T> Members
public int IndexOf(T item)
{
return _innerList.Select(wr => wr.Target).IndexOf(item);
}
public void Insert(int index, T item)
{
_innerList.Insert(index, new WeakReference<T>(item));
}
public void RemoveAt(int index)
{
_innerList.RemoveAt(index);
}
public T this[int index]
{
get
{
return _innerList[index].Target;
}
set
{
_innerList[index] = new WeakReference<T>(value);
}
}
#endregion
#region ICollection<T> Members
public void Add(T item)
{
_innerList.Add(new WeakReference<T>(item));
}
public void Clear()
{
_innerList.Clear();
}
public bool Contains(T item)
{
return _innerList.Any(wr => object.Equals(wr.Target, item));
}
public void CopyTo(T[] array, int arrayIndex)
{
_innerList.Select(wr => wr.Target).CopyTo(array, arrayIndex);
}
public int Count
{
get { return _innerList.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(T item)
{
int index = IndexOf(item);
if (index > -1)
{
RemoveAt(index);
return true;
}
return false;
}
#endregion
#region IEnumerable<T> Members
public IEnumerator<T> GetEnumerator()
{
return _innerList.Select(x => x.Target).GetEnumerator();
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
#endregion
public void Purge()
{
_innerList.RemoveAll(wr => !wr.IsAlive);
}
}
このクラスは、次のクラスと拡張メソッドを使用します。
WeakReference<T>
(強く型付けされたラッパーの周りWeakReference
)
[Serializable]
public class WeakReference<T> : WeakReference
{
public WeakReference(T target)
: base(target)
{
}
public WeakReference(T target, bool trackResurrection)
: base(target, trackResurrection)
{
}
public WeakReference(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
public new T Target
{
get
{
return (T)base.Target;
}
}
}
IndexOf
(と同じIList<T>.IndexOf
ですが、で動作しますIEnumerable<T>
)
public static int IndexOf<T>(this IEnumerable<T> source, T item)
{
var entry = source.Select((x, i) => new { Value = x, Index = i })
.Where(x => object.Equals(x.Value, item))
.FirstOrDefault();
return entry != null ? entry.Index : -1;
}
CopyTo
(と同じIList<T>.CopyTo
ですが、で動作しますIEnumerable<T>
)
public static void CopyTo<T>(this IEnumerable<T> source, T[] array, int startIndex)
{
int lowerBound = array.GetLowerBound(0);
int upperBound = array.GetUpperBound(0);
if (startIndex < lowerBound)
throw new ArgumentOutOfRangeException("startIndex", "The start index must be greater than or equal to the array lower bound");
if (startIndex > upperBound)
throw new ArgumentOutOfRangeException("startIndex", "The start index must be less than or equal to the array upper bound");
int i = 0;
foreach (var item in source)
{
if (startIndex + i > upperBound)
throw new ArgumentException("The array capacity is insufficient to copy all items from the source sequence");
array[startIndex + i] = item;
i++;
}
}
.NET 2.0または3.5でConditionalWeakTableを使用する必要がある場合は、https ://github.com/theraot/Theraot/wiki/Featuresにバックポートがあります。
java.util.WeakHashMapを使用して、オブジェクトをキーに格納するのはどうですか?値は任意のダミーオブジェクトにすることができます。ただし、マップは順序付けられていないため、WeakSet機能しか取得できません。