Is there a way to do a WeakList or WeakCollection (like WeakReference) in CLR?

笑着哭i 提交于 2019-12-30 16:24:01

问题


Using a List<WeakReference> will not work as I want. What I want is for WeakReferences to be automatically removed from the list whenever the object they reference is garbage collected.

ConditionalWeakTable<TKey,TValue> does not satisfy me either, because although its keys and values are weakly referenced and collectable, you cannot enumerate them!


回答1:


I agree that implementing a WeakList<T> is possible, but I don't think it's exactly easy. You're welcome to use my implementation here. The WeakCollection<T> class depends on WeakReference<T>, which in turn depends on SafeGCHandle.




回答2:


You could easily implement a WeakList<T> class, which would wrap a List<WeakReference>.

There is no way to automatically remove objects when they are garbage collected, because it's not possible to detect when this happens. However, you could remove "dead" (garbage collected) objects when you encounter them, by checking the WeakReference.IsAlive property. However, I wouldn't recommend this approach, because it could lead to confusing behavior from the client's point of view. Instead, I would recommend implementing a Purge method to remove dead entries, that you would call explicitly.

Here's a sample implementation :

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);
    }
}

This class uses the following classes and extension methods :

WeakReference<T> (just a strongly typed wrapper around 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 (same as IList<T>.IndexOf, but works on a 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 (same as IList<T>.CopyTo, but works on a 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++;
        }
    }



回答3:


For anybody needing to use a ConditionalWeakTable in .NET 2.0 or 3.5 there is a backport of it here: https://github.com/theraot/Theraot/wiki/Features



来源:https://stackoverflow.com/questions/2837478/is-there-a-way-to-do-a-weaklist-or-weakcollection-like-weakreference-in-clr

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!