Sie könnten leicht eine WeakList<T>
Klasse implementieren, die eine List<WeakReference>
umhüllen würde.
Es gibt keine Möglichkeit, Objekte automatisch zu entfernen, wenn sie nicht ordnungsgemäß verarbeitet werden, da dies nicht erkannt werden kann. Sie können jedoch "tote" (Garbage Collection) Objekte entfernen, wenn Sie auf diese stoßen, indem Sie die Eigenschaft WeakReference.IsAlive
überprüfen. Ich würde diesen Ansatz jedoch nicht empfehlen, da dies aus Sicht des Kunden zu einem verwirrenden Verhalten führen könnte. Stattdessen würde ich empfehlen, eine Purge
-Methode zu implementieren, um tote Einträge zu entfernen, die Sie explizit aufrufen würden.
Hier ist eine Beispielimplementierung:
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);
}
}
Diese Klasse verwendet die folgenden Klassen und Erweiterungsmethoden:
WeakReference<T>
(nur eine stark typisierte Wrapper um 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
(gleich wie IList<T>.IndexOf
, arbeitet aber auf einem 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
(gleiche wie IList<T>.CopyTo
, arbeitet aber auf einem 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++;
}
}
Interessante zwei Antworten zu sehen, so weit haben beide eine nicht-vollautomatische Reinigungsschritt. Ich muss einige Zeit darüber nachdenken, aber es könnte tatsächlich gut genug für das sein, was ich brauche, auch wenn es nicht vollautomatisch ist. –
Das Säubern geschieht am natürlichsten während der Aufzählung. Die einzige andere Option ist eine periodische Bereinigung, in welchem Fall die Lösung eher ein "Cache" als eine "schwache Liste" wird. 'WeakReference' soll nicht zum Caching verwendet werden; Dafür gibt es bessere Lösungen (z. B. [System.Runtime.Caching] (http://msdn.microsoft.com/en-us/library/system.runtime.caching.aspx)). –
Danke für den interessanten Vorschlag über System.Runtime.Caching. Aber ich hatte eine bestimmte Anwendung für diese Frage im Sinn, und ich kann einige Impendance Mismatches sehen - 1) Ich brauche nicht oder möchte String-Schlüssel verwenden, um Elemente zu bekommen, ich möchte nur in der Lage sein, sie auf Nachfrage zu iterieren.2) Ich wäre wahrscheinlich glücklicher, wenn Elemente den Cache nur aufgrund von Garbage Collection verlassen würden, und nicht aus anderen Gründen (wie Cache, der zu viel Speicher verbraucht). –